3 //============================================================================
7 // Implementation of value-related CDL classes.
9 //============================================================================
10 //####COPYRIGHTBEGIN####
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2002 Bart Veer
14 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
16 // This file is part of the eCos host tools.
18 // This program is free software; you can redistribute it and/or modify it
19 // under the terms of the GNU General Public License as published by the Free
20 // Software Foundation; either version 2 of the License, or (at your option)
23 // This program is distributed in the hope that it will be useful, but WITHOUT
24 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
25 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
28 // You should have received a copy of the GNU General Public License along with
29 // this program; if not, write to the Free Software Foundation, Inc.,
30 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
32 // ----------------------------------------------------------------------------
34 //####COPYRIGHTEND####
35 //============================================================================
36 //#####DESCRIPTIONBEGIN####
43 //####DESCRIPTIONEND####
44 //============================================================================
49 // ----------------------------------------------------------------------------
50 #include "cdlconfig.h"
52 // Get the infrastructure types, assertions, tracing and similar
54 #include <cyg/infra/cyg_ass.h>
55 #include <cyg/infra/cyg_trac.h>
57 // <cdlcore.hxx> defines everything implemented in this module.
58 // It implicitly supplies <string>, <vector> and <map> because
59 // the class definitions rely on these headers.
60 #include <cdlcore.hxx>
66 // ----------------------------------------------------------------------------
67 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValue);
68 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListValue);
69 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValuableBody);
72 //{{{ CdlSimpleValue class
76 // ----------------------------------------------------------------------------
78 CdlSimpleValue::CdlSimpleValue()
80 CYG_REPORT_FUNCNAME("CdlSimpleValue:: default constructor");
81 CYG_REPORT_FUNCARG1XV(this);
86 valid_flags = int_valid | double_valid | string_valid;
87 format = CdlValueFormat_Default;
92 CdlSimpleValue::CdlSimpleValue(std::string val)
94 CYG_REPORT_FUNCNAME("CdlSimpleValue:: string constructor");
95 CYG_REPORT_FUNCARG1XV(this);
100 valid_flags = string_valid;
101 format = CdlValueFormat_Default;
106 CdlSimpleValue::CdlSimpleValue(cdl_int val)
108 CYG_REPORT_FUNCNAME("CdlSimpleValue:: int constructor");
109 CYG_REPORT_FUNCARG1XV(this);
114 valid_flags = int_valid;
115 format = CdlValueFormat_Default;
120 CdlSimpleValue::CdlSimpleValue(double val)
122 CYG_REPORT_FUNCNAME("CdlSimpleValue:: double constructor");
123 CYG_REPORT_FUNCARG1XV(this);
128 valid_flags = double_valid;
129 format = CdlValueFormat_Default;
134 CdlSimpleValue::CdlSimpleValue(bool val)
136 CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool constructor");
137 CYG_REPORT_FUNCARG2XV(this, val);
139 value = (val) ? "1" : "0";
140 int_value = (val) ? 1 : 0;
142 valid_flags = string_valid | int_valid;
143 format = CdlValueFormat_Default;
148 CdlSimpleValue::CdlSimpleValue(const CdlSimpleValue& original)
150 CYG_REPORT_FUNCNAME("CdlSimpleValue:: copy constructor");
151 CYG_REPORT_FUNCARG2XV(this, &original);
153 value = original.value;
154 int_value = original.int_value;
155 double_value = original.double_value;
156 valid_flags = original.valid_flags;
157 format = original.format;
165 // ----------------------------------------------------------------------------
167 CdlSimpleValue::~CdlSimpleValue()
169 CYG_REPORT_FUNCNAME("CdlsimpleValue:: destructor");
170 CYG_REPORT_FUNCARG1XV(this);
176 format = CdlValueFormat_Default;
182 //{{{ Assignment operators
184 // ----------------------------------------------------------------------------
187 CdlSimpleValue::operator=(const CdlSimpleValue& original)
189 CYG_REPORT_FUNCNAME("CdlSimpleValue:: assignment operator");
190 CYG_REPORT_FUNCARG2XV(this, &original);
192 if (this != &original) {
193 value = original.value;
194 int_value = original.int_value;
195 double_value = original.double_value;
196 valid_flags = original.valid_flags;
197 format = original.format;
205 CdlSimpleValue::operator=(std::string val)
207 CYG_REPORT_FUNCNAME("CdlSimpleValue:: string assignment");
208 CYG_REPORT_FUNCARG1XV(this);
213 valid_flags = string_valid;
214 format = CdlValueFormat_Default;
221 CdlSimpleValue::operator=(cdl_int val)
223 CYG_REPORT_FUNCNAME("CdlSimpleValue:: integer assignment");
224 CYG_REPORT_FUNCARG1XV(this);
229 valid_flags = int_valid;
230 format = CdlValueFormat_Default;
237 CdlSimpleValue::operator=(double val)
239 CYG_REPORT_FUNCNAME("CdlSimpleValue:: double assignment");
240 CYG_REPORT_FUNCARG1XV(this);
245 valid_flags = double_valid;
246 format = CdlValueFormat_Default;
252 // ----------------------------------------------------------------------------
253 // Converting a boolean into a simple value. This is sufficiently common
254 // to warrant its own member function, and in addition it avoids
255 // ambiguity when assigning 0.
258 CdlSimpleValue::operator=(bool val)
260 CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool assignment");
261 CYG_REPORT_FUNCARG1XV(this);
263 value = (val) ? "1" : "0";
264 int_value = (val) ? 1 : 0;
266 valid_flags = string_valid | int_valid;
267 format = CdlValueFormat_Default;
274 //{{{ CdlValuable -> CdlSimpleValue
276 // ----------------------------------------------------------------------------
277 // This routine bridges the gap between the full data held in the CdlValuable
278 // object and the basic information needed for expression evaluation.
281 CdlSimpleValue::eval_valuable(CdlEvalContext& context, CdlValuable valuable, CdlSimpleValue& result)
283 CYG_REPORT_FUNCNAME("CdlSimpleValue:: valuable assignment");
284 CYG_REPORT_FUNCARG3XV(&context, valuable, &result);
285 CYG_PRECONDITION_CLASSC(valuable);
287 // If the valuable is not currently active then its value is
288 // always zero for the purposes of expression evaluation.
289 // FIXME: this check should be on a per-transaction basis.
290 if (((0 != context.transaction) && !context.transaction->is_active(valuable)) ||
291 ((0 == context.transaction) && !valuable->is_active())) {
294 result.int_value = 0;
295 result.double_value = 0.0;
296 result.valid_flags = string_valid | int_valid;
297 result.format = CdlValueFormat_Default;
302 // Get hold of the underlying CdlValue object
303 const CdlValue& val = (0 != context.transaction) ?
304 context.transaction->get_whole_value(valuable) : valuable->get_whole_value();
306 // Otherwise the value depends on the flavor.
307 switch(val.get_flavor()) {
308 case CdlValueFlavor_None :
310 // This could be treated as an error, but since valuables with flavor
311 // none are permanently enabled a constant "1" is a better result.
313 result.int_value = 1;
314 result.double_value = 0.0;
315 result.valid_flags = string_valid | int_valid;
316 result.format = CdlValueFormat_Default;
319 case CdlValueFlavor_Bool :
321 bool enabled = val.is_enabled();
322 result.value = (enabled) ? "1" : "0";
323 result.int_value = (enabled) ? 1 : 0;
324 result.double_value = 0.0;
325 result.valid_flags = string_valid | int_valid;
326 result.format = CdlValueFormat_Default;
329 case CdlValueFlavor_BoolData :
331 if (!val.is_enabled()) {
334 result.int_value = 0;
335 result.double_value = 0.0;
336 result.valid_flags = string_valid | int_valid;
337 result.format = CdlValueFormat_Default;
341 // Just use a copy constructor, let the compiler optimise things.
342 result = val.get_simple_value();
346 case CdlValueFlavor_Data :
348 // Just like BoolData, but with no need to check the enabled flag.
349 result = val.get_simple_value();
354 CYG_FAIL("Valuable object with an unknown flavor encountered.");
362 //{{{ Getting the value
364 // ----------------------------------------------------------------------------
365 // Some of these calls involve conversion operators.
368 CdlSimpleValue::get_value() const
370 CYG_REPORT_FUNCNAME("CdlSimpleValue::get_value");
371 CYG_REPORT_FUNCARG1XV(this);
373 if (!(valid_flags & string_valid)) {
374 if (valid_flags & int_valid) {
375 Cdl::integer_to_string(int_value, value, format);
376 } else if (valid_flags & double_valid) {
377 Cdl::double_to_string(double_value, value, format);
379 CYG_FAIL("Attempt to use uninitialized SimpleValue");
381 valid_flags |= string_valid;
389 CdlSimpleValue::has_integer_value() const
391 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_integer_value", "result %d");
392 CYG_REPORT_FUNCARG1XV(this);
394 if (!(valid_flags & (int_valid | int_invalid))) {
395 if (valid_flags & double_valid) {
396 if (Cdl::double_to_integer(double_value, int_value)) {
397 valid_flags |= int_valid;
399 valid_flags |= int_invalid;
401 } else if (valid_flags & string_valid) {
402 if (Cdl::string_to_integer(value, int_value)) {
403 valid_flags |= int_valid;
405 valid_flags |= int_invalid;
408 CYG_FAIL("Attempt to use uninitialized SimpleValue");
412 bool result = (valid_flags & int_valid);
413 CYG_REPORT_RETVAL(result);
418 CdlSimpleValue::get_integer_value() const
420 CYG_REPORT_FUNCNAMETYPE("CdlsimpleValue::get_integer_value", "result %ld");
421 CYG_REPORT_FUNCARG1XV(this);
424 if ((valid_flags & int_valid) || has_integer_value()) {
428 CYG_REPORT_RETVAL((int) result);
433 CdlSimpleValue::has_double_value() const
435 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_double_value", "result %d");
436 CYG_REPORT_FUNCARG1XV(this);
438 if (!(valid_flags & (double_valid | double_invalid))) {
439 if (valid_flags & int_valid) {
440 Cdl::integer_to_double(int_value, double_value);
441 valid_flags |= double_valid;
442 } else if (valid_flags & string_valid) {
443 if (Cdl::string_to_double(value, double_value)) {
444 valid_flags |= double_valid;
446 valid_flags |= double_invalid;
449 CYG_FAIL("Attempt to use uninitialized SimpleValue");
452 bool result = (valid_flags & double_valid);
453 CYG_REPORT_RETVAL(result);
458 CdlSimpleValue::get_double_value() const
460 CYG_REPORT_FUNCNAME("CdlSimpleValue::get_double_value");
461 CYG_REPORT_FUNCARG1XV(this);
464 if ((valid_flags & double_valid) || has_double_value()) {
465 result = double_value;
473 CdlSimpleValue::get_bool_value() const
475 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_bool_value", "result %d");
476 CYG_REPORT_FUNCARG1XV(this);
479 if (valid_flags & int_valid) {
480 if (0 != int_value) {
483 } else if (valid_flags & double_valid) {
484 // Leave it to the compiler to decide what is valid
485 result = double_value;
486 } else if (valid_flags & string_valid) {
487 // string_to_bool copes with "1", "true", and a few other cases.
488 // If the current value does not match any of these then
489 // true corresponds to a non-empty string.
490 if (!Cdl::string_to_bool(value, result)) {
498 // No value defined, default to false.
502 CYG_REPORT_RETVAL(result);
507 //{{{ Updating the value
509 // ----------------------------------------------------------------------------
510 // Normally the assignment operators will be used for this instead.
513 CdlSimpleValue::set_value(std::string val, CdlValueFormat new_format)
515 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value (string)");
516 CYG_REPORT_FUNCARG1XV(this);
521 valid_flags = string_valid;
527 CdlSimpleValue::set_integer_value(cdl_int val, CdlValueFormat new_format)
529 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_integer_value");
530 CYG_REPORT_FUNCARG2XV(this, (int) val);
535 valid_flags = int_valid;
543 CdlSimpleValue::set_double_value(double val, CdlValueFormat new_format)
545 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_double_value");
546 CYG_REPORT_FUNCARG1XV(this);
551 valid_flags = double_valid;
558 //{{{ Value format support
560 // ----------------------------------------------------------------------------
563 CdlSimpleValue::get_value_format() const
565 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_value_format", "result %d");
566 CYG_REPORT_FUNCARG1XV(this);
568 CdlValueFormat result = format;
569 CYG_REPORT_RETVAL(result);
574 CdlSimpleValue::set_value_format(CdlValueFormat new_format)
576 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
577 CYG_REPORT_FUNCARG2XV(this, new_format);
585 CdlSimpleValue::set_value_format(CdlSimpleValue& other_val)
587 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format (simple val)");
588 CYG_REPORT_FUNCARG2XV(this, &other_val);
590 format = other_val.format;
595 // This gets used for binary operators, e.g. A + B
596 // If A has a non-default format then that gets used.
597 // Otherwise B's format gets used, which may or may not be default.
599 // e.g. 0x1000 + 4 -> 0x1004
600 // 10 + 0x100 -> 0x10A
604 CdlSimpleValue::set_value_format(CdlSimpleValue& val1, CdlSimpleValue& val2)
606 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
607 CYG_REPORT_FUNCARG3XV(this, &val1, &val2);
609 format = (CdlValueFormat_Default != val1.format) ? val1.format : val2.format;
615 //{{{ Comparison operators
617 // ----------------------------------------------------------------------------
620 CdlSimpleValue::operator==(const CdlSimpleValue& other) const
622 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator==", "result %d");
623 CYG_REPORT_FUNCARG2XV(this, &other);
627 if (has_integer_value()) {
628 if (other.has_integer_value()) {
629 cdl_int val1 = get_integer_value();
630 cdl_int val2 = other.get_integer_value();
631 result = (val1 == val2);
633 } else if (has_double_value()) {
634 if (other.has_double_value()) {
635 double val1 = get_double_value();
636 double val2 = other.get_double_value();
637 result = (val1 == val2);
640 std::string val1 = get_value();
641 std::string val2 = other.get_value();
642 result = (val1 == val2);
645 CYG_REPORT_RETVAL(result);
650 CdlSimpleValue::operator!=(const CdlSimpleValue& other) const
652 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator!=", "result %d");
653 CYG_REPORT_FUNCARG2XV(this, &other);
656 if (has_integer_value()) {
657 if (other.has_integer_value()) {
658 cdl_int val1 = get_integer_value();
659 cdl_int val2 = other.get_integer_value();
660 result = (val1 != val2);
662 } else if (has_double_value()) {
663 if (other.has_double_value()) {
664 double val1 = get_double_value();
665 double val2 = other.get_double_value();
666 result = (val1 != val2);
669 std::string val1 = get_value();
670 std::string val2 = other.get_value();
671 result = (val1 != val2);
675 CYG_REPORT_RETVAL(result);
684 // ----------------------------------------------------------------------------
685 // This should really be a class static constant, but VC++ does not implement
686 // that part of the language. A constant here avoids the need for lots of
687 // occurrences of 4 throughout the value-related routines.
689 static const int CdlValue_number_of_sources = 4;
693 // ----------------------------------------------------------------------------
694 // The default flavor depends on the type of entity being created. For
695 // example CDL options are boolean by default, but packages are booldata.
696 // The intelligence to do the right thing lives in set_flavor().
698 CdlValue::CdlValue(CdlValueFlavor flavor_arg)
700 CYG_REPORT_FUNCNAME("CdlValue:: constructor");
701 CYG_REPORT_FUNCARG1XV(this);
703 current_source = CdlValueSource_Default;
704 source_valid[CdlValueSource_Default] = true;
705 source_valid[CdlValueSource_Inferred] = false;
706 source_valid[CdlValueSource_Wizard] = false;
707 source_valid[CdlValueSource_User] = false;
708 enabled[CdlValueSource_Default] = false;
709 enabled[CdlValueSource_Inferred] = false;
710 enabled[CdlValueSource_Wizard] = false;
711 enabled[CdlValueSource_User] = false;
713 // The SimpleValues will initialize themselves.
715 cdlvalue_cookie = CdlValue_Magic;
716 CYGDBG_MEMLEAK_CONSTRUCTOR();
718 // This cannot happen until after the object is valid.
719 set_flavor(flavor_arg);
721 CYG_POSTCONDITION_THISC();
725 // ----------------------------------------------------------------------------
726 // Copy constructor. This is not really required, a default
727 // member-wise copy would be fine and more efficient, but it would
728 // lose tracing and assertion.
730 CdlValue::CdlValue(const CdlValue& original)
732 CYG_REPORT_FUNCNAME("CdlValue:: copy constructor");
733 CYG_REPORT_FUNCARG2XV(this, &original);
734 CYG_INVARIANT_CLASSOC(CdlValue, original);
736 flavor = original.flavor;
737 current_source = original.current_source;
738 for (int i = 0; i < CdlValue_number_of_sources; i++) {
739 source_valid[i] = original.source_valid[i];
740 enabled[i] = original.enabled[i];
741 values[i] = original.values[i];
744 cdlvalue_cookie = CdlValue_Magic;
745 CYGDBG_MEMLEAK_CONSTRUCTOR();
747 CYG_POSTCONDITION_THISC();
751 // ----------------------------------------------------------------------------
752 // Assignment operator. Again this is not required, the default would be
753 // fine and more efficient, but tracing and assertions are good things.
755 CdlValue& CdlValue::operator=(const CdlValue& original)
757 CYG_REPORT_FUNCNAME("CdlValue:: assignment operator");
758 CYG_REPORT_FUNCARG2XV(this, &original);
759 CYG_INVARIANT_CLASSOC(CdlValue, original);
761 if (this != &original) {
762 flavor = original.flavor;
763 current_source = original.current_source;
764 for (int i = 0; i < CdlValue_number_of_sources; i++) {
765 source_valid[i] = original.source_valid[i];
766 enabled[i] = original.enabled[i];
767 values[i] = original.values[i];
771 cdlvalue_cookie = CdlValue_Magic;
772 CYG_POSTCONDITION_THISC();
780 // ----------------------------------------------------------------------------
782 CdlValue::~CdlValue()
784 CYG_REPORT_FUNCNAME("CdlValue:: destructor");
785 CYG_REPORT_FUNCARG1XV(this);
786 CYG_PRECONDITION_THISC();
788 cdlvalue_cookie = CdlValue_Invalid;
789 flavor = CdlValueFlavor_Invalid;
790 current_source = CdlValueSource_Invalid;
791 for (int i = 0; i < CdlValue_number_of_sources; i++) {
792 source_valid[i] = false;
794 // The CdlSimpleValue array will take care of itself.
796 CYGDBG_MEMLEAK_DESTRUCTOR();
804 // ----------------------------------------------------------------------------
806 CdlValue::check_this(cyg_assert_class_zeal zeal) const
808 if (CdlValue_Magic != cdlvalue_cookie) {
811 CYGDBG_MEMLEAK_CHECKTHIS();
813 if (!source_valid[CdlValueSource_Default]) {
817 if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Data == flavor)) {
818 for (int i = 0; i < CdlValue_number_of_sources; i++) {
824 for (int i = 0; i < CdlValue_number_of_sources; i++) {
825 if (source_valid[i]) {
826 if (!values[i].check_this(zeal)) {
836 //{{{ Flavor manipulation
838 // ----------------------------------------------------------------------------
839 // Get hold of the current flavor.
841 CdlValue::get_flavor(void) const
843 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_flavor", "result %d");
844 CYG_REPORT_FUNCARG1XV(this);
845 CYG_PRECONDITION_THISC();
847 CdlValueFlavor result = flavor;
848 CYG_REPORT_RETVAL(result);
852 // ----------------------------------------------------------------------------
853 // set_flavor() may be invoked once or twice for a given entity. The first
854 // time is from inside the constructor with the default flavor for this
855 // particular class of entity. It may then be called again if the
856 // entity has a "flavor" property that overrides this. All old data
857 // will be lost, so evaluating a default value etc. should be done after
858 // the call to set_flavor(), and there should be no subsequent calls to
862 CdlValue::set_flavor(CdlValueFlavor flavor_arg)
864 CYG_REPORT_FUNCNAME("CdlValue:: set_flavor");
865 CYG_REPORT_FUNCARG2XV(this, flavor_arg);
867 // No precondition here, set_flavor() is called from inside the constructor
868 CYG_PRECONDITIONC((CdlValueFlavor_None == flavor_arg) || \
869 (CdlValueFlavor_Bool == flavor_arg) || \
870 (CdlValueFlavor_BoolData == flavor_arg) || \
871 (CdlValueFlavor_Data == flavor_arg));
875 case CdlValueFlavor_None :
877 // All value sources are enabled, but "default" remains
878 // the only valid one. All data parts are set to "1",
879 // although that should not really matter.
880 enabled[CdlValueSource_Default] = true;
881 enabled[CdlValueSource_Inferred] = true;
882 enabled[CdlValueSource_Wizard] = true;
883 enabled[CdlValueSource_User] = true;
885 CdlSimpleValue simple_val((cdl_int) 1);
886 values[CdlValueSource_Default] = simple_val;
887 values[CdlValueSource_Inferred] = simple_val;
888 values[CdlValueSource_Wizard] = simple_val;
889 values[CdlValueSource_User] = simple_val;
893 case CdlValueFlavor_Bool :
895 // All value sources start out as disabled, but with a
896 // constant data part of 1. Users can only control the
897 // boolean part. This is consistent with header file
898 // generation: no #define is generated for disabled
899 // options, but if the option is enabled then the data
900 // part will be used for the value.
901 enabled[CdlValueSource_Default] = false;
902 enabled[CdlValueSource_Inferred] = false;
903 enabled[CdlValueSource_Wizard] = false;
904 enabled[CdlValueSource_User] = false;
906 // BLV - keep the data part at 0 for now. There is too
907 // much confusion in the code between value as a string
908 // representation, and value as the data part of the
909 // bool/data pair. This needs to be fixed, but it requires
910 // significant API changes.
912 CdlSimpleValue simple_val(cdl_int(1));
914 CdlSimpleValue simple_val(cdl_int(0));
916 values[CdlValueSource_Default] = simple_val;
917 values[CdlValueSource_Inferred] = simple_val;
918 values[CdlValueSource_Wizard] = simple_val;
919 values[CdlValueSource_User] = simple_val;
923 case CdlValueFlavor_BoolData :
925 // All value sources start out as disabled, just like
926 // booleans. Nothing is known about the data part.
927 enabled[CdlValueSource_Default] = false;
928 enabled[CdlValueSource_Inferred] = false;
929 enabled[CdlValueSource_Wizard] = false;
930 enabled[CdlValueSource_User] = false;
934 case CdlValueFlavor_Data :
936 // All value sources start out as enabled, and cannot be
937 // changed. Nothing is known about the data part.
938 enabled[CdlValueSource_Default] = true;
939 enabled[CdlValueSource_Inferred] = true;
940 enabled[CdlValueSource_Wizard] = true;
941 enabled[CdlValueSource_User] = true;
953 //{{{ Source manipulation
955 // ----------------------------------------------------------------------------
958 CdlValue::set_source(CdlValueSource source)
960 CYG_REPORT_FUNCNAME("CdlValue::set_source");
961 CYG_REPORT_FUNCARG2XV(this, source);
962 CYG_INVARIANT_THISC(CdlValue);
963 CYG_PRECONDITIONC((0 <= source) && (source <= CdlValue_number_of_sources));
964 CYG_PRECONDITIONC(source_valid[source]);
966 current_source = source;
972 CdlValue::get_source(void) const
974 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_source", "source %d");
975 CYG_REPORT_FUNCARG1XV(this);
976 CYG_PRECONDITION_THISC();
978 CdlValueSource result = current_source;
979 CYG_REPORT_RETVAL(result);
984 CdlValue::has_source(CdlValueSource source) const
986 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_source", "result %d");
987 CYG_REPORT_FUNCARG2XV(this, source);
988 CYG_PRECONDITION_THISC();
989 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
991 bool result = source_valid[source];
992 CYG_REPORT_RETVAL(result);
996 // ----------------------------------------------------------------------------
997 // Invalidate a specific source. If that source happens to be the current one,
998 // switch to the highest-priority valid source.
1001 CdlValue::invalidate_source(CdlValueSource source)
1003 CYG_REPORT_FUNCNAME("CdlValue::invalidate_source");
1004 CYG_REPORT_FUNCARG2XV(this, source);
1005 CYG_PRECONDITION_THISC();
1006 CYG_PRECONDITIONC(CdlValueSource_Default != source);
1007 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1009 if (CdlValueSource_Default != source) {
1010 source_valid[source] = false;
1011 if (current_source == source) {
1012 if (source_valid[CdlValueSource_User]) {
1013 current_source = CdlValueSource_User;
1014 } else if (source_valid[CdlValueSource_Wizard]) {
1015 current_source = CdlValueSource_Wizard;
1016 } else if (source_valid[CdlValueSource_Inferred]) {
1017 current_source = CdlValueSource_Inferred;
1019 current_source = CdlValueSource_Default;
1024 CYG_POSTCONDITIONC(source_valid[current_source]);
1028 //{{{ Retrieving the data
1030 // ----------------------------------------------------------------------------
1031 // Check the enabled flag for the appropriate source. The specified source
1032 // is normally provided by a default argument CdlValueSource_Current, which
1033 // 99.9...% of the time is what we are after.
1035 // Note that this member can be used even for entities of flavor none
1036 // and data, and the result will be true. However it is not legal to
1037 // disable such entities.
1040 CdlValue::is_enabled(CdlValueSource source) const
1042 CYG_REPORT_FUNCNAMETYPE("CdlValue::is_enabled", "enabled %d");
1043 CYG_REPORT_FUNCARG2XV(this, source);
1044 CYG_PRECONDITION_THISC();
1046 if (CdlValueSource_Current == source) {
1047 source = current_source;
1049 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1050 CYG_PRECONDITIONC(source_valid[source]);
1052 bool result = enabled[source];
1053 CYG_REPORT_RETVAL(result);
1057 // ----------------------------------------------------------------------------
1058 // Access to the value field.
1061 CdlValue::get_value(CdlValueSource source) const
1063 CYG_REPORT_FUNCNAME("CdlValue::get_value");
1064 CYG_REPORT_FUNCARG2XV(this, source);
1065 CYG_PRECONDITION_THISC();
1067 if (CdlValueSource_Current == source) {
1068 source = current_source;
1070 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1071 CYG_PRECONDITIONC(source_valid[source]);
1073 std::string result = values[source].get_value();
1074 CYG_REPORT_RETURN();
1079 CdlValue::has_integer_value(CdlValueSource source) const
1081 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_integer_value", "result %d");
1082 CYG_REPORT_FUNCARG2XV(this, source);
1083 CYG_INVARIANT_THISC(CdlValue);
1085 if (CdlValueSource_Current == source) {
1086 source = current_source;
1088 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1089 CYG_PRECONDITIONC(source_valid[source]);
1091 bool result = values[source].has_integer_value();
1092 CYG_REPORT_RETVAL(result);
1097 CdlValue::has_double_value(CdlValueSource source) const
1099 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_value", "result %d");
1100 CYG_REPORT_FUNCARG2XV(this, source);
1101 CYG_INVARIANT_THISC(CdlValue);
1103 if (CdlValueSource_Current == source) {
1104 source = current_source;
1106 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1107 CYG_PRECONDITIONC(source_valid[source]);
1109 bool result = values[source].has_double_value();
1110 CYG_REPORT_RETVAL(result);
1115 CdlValue::get_integer_value(CdlValueSource source) const
1117 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_integer_value", "value %ld");
1118 CYG_REPORT_FUNCARG2XV(this, source);
1119 CYG_PRECONDITION_THISC();
1121 if (CdlValueSource_Current == source) {
1122 source = current_source;
1124 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1125 CYG_PRECONDITIONC(source_valid[source]);
1127 cdl_int result = values[source].get_integer_value();
1128 CYG_REPORT_RETVAL(result);
1133 CdlValue::get_double_value(CdlValueSource source) const
1135 CYG_REPORT_FUNCNAME("CdlValue::get_double_value");
1136 CYG_REPORT_FUNCARG2XV(this, source);
1137 CYG_PRECONDITION_THISC();
1139 if (CdlValueSource_Current == source) {
1140 source = current_source;
1142 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1143 CYG_PRECONDITIONC(source_valid[source]);
1145 double result = values[source].get_double_value();
1146 CYG_REPORT_RETURN();
1151 CdlValue::get_simple_value(CdlValueSource source) const
1153 CYG_REPORT_FUNCNAME("CdlValue::get_simple_value");
1154 CYG_REPORT_FUNCARG2XV(this, source);
1155 CYG_PRECONDITION_THISC();
1157 if (CdlValueSource_Current == source) {
1158 source = current_source;
1160 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1161 CYG_PRECONDITIONC(source_valid[source]);
1163 CYG_REPORT_RETURN();
1164 return values[source];
1168 //{{{ Value modification
1170 // ----------------------------------------------------------------------------
1173 CdlValue::set_enabled(bool val, CdlValueSource source)
1175 CYG_REPORT_FUNCNAME("CdlValue::set_enabled");
1176 CYG_REPORT_FUNCARG3XV(this, val, source);
1177 CYG_INVARIANT_THISC(CdlValue);
1178 CYG_PRECONDITIONC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
1179 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1181 enabled[source] = val;
1182 source_valid[source] = true;
1183 if (source > current_source) {
1184 current_source = source;
1187 CYG_REPORT_RETURN();
1191 CdlValue::set_value(CdlSimpleValue& val, CdlValueSource source)
1193 CYG_REPORT_FUNCNAME("CdlValue::set_value");
1194 CYG_REPORT_FUNCARG3XV(this, &val, source);
1195 CYG_INVARIANT_THISC(CdlValue);
1196 CYG_PRECONDITIONC((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1197 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1199 values[source] = val;
1200 source_valid[source] = true;
1201 if (source > current_source) {
1202 current_source = source;
1205 CYG_REPORT_RETURN();
1209 CdlValue::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
1211 CYG_REPORT_FUNCNAME("CdlValue::set_enabled_and_value");
1212 CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
1213 CYG_INVARIANT_THISC(CdlValue);
1214 CYG_PRECONDITIONC(CdlValueFlavor_BoolData == flavor);
1215 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1217 enabled[source] = enabled_arg;
1218 values[source] = val;
1219 source_valid[source] = true;
1220 if (source > current_source) {
1221 current_source = source;
1224 CYG_REPORT_RETURN();
1227 // ----------------------------------------------------------------------------
1228 // Given a SimpleValue, this member function does the right thing
1232 CdlValue::set(CdlSimpleValue& val, CdlValueSource source)
1234 CYG_REPORT_FUNCNAME("CdlValue::set");
1235 CYG_REPORT_FUNCARG3XV(this, &val, source);
1236 CYG_INVARIANT_THISC(CdlValue);
1237 CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1238 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1241 case CdlValueFlavor_Bool:
1242 enabled[source] = val.get_bool_value();
1245 case CdlValueFlavor_BoolData:
1246 if (!val.get_bool_value()) {
1247 enabled[source] = false;
1248 values[source] = (cdl_int) 0;
1250 enabled[source] = true;
1251 values[source] = val;
1255 case CdlValueFlavor_Data:
1256 values[source] = val;
1260 CYG_FAIL("Unknown value flavor detected.");
1263 source_valid[source] = true;
1264 if (source > current_source) {
1265 current_source = source;
1268 CYG_REPORT_RETURN();
1274 //{{{ CdlListValue class
1276 // ----------------------------------------------------------------------------
1277 // List values. Most of this is straightforward.
1279 CdlListValue::CdlListValue()
1281 CYG_REPORT_FUNCNAME("CdlListValue:: default constructor");
1282 CYG_REPORT_FUNCARG1XV(this);
1284 // The only data fields are embedded objects which will have been
1285 // filled in already.
1286 cdllistvalue_cookie = CdlListValue_Magic;
1287 CYGDBG_MEMLEAK_CONSTRUCTOR();
1289 CYG_POSTCONDITION_THISC();
1290 CYG_REPORT_RETURN();
1293 CdlListValue::CdlListValue(const CdlListValue& original)
1295 CYG_REPORT_FUNCNAME("CdlListValue:: copy constructor");
1296 CYG_REPORT_FUNCARG2XV(this, &original);
1297 CYG_INVARIANT_CLASSOC(CdlListValue, original);
1299 // This may get expensive, but should not happen very often.
1300 table = original.table;
1301 integer_ranges = original.integer_ranges;
1302 double_ranges = original.double_ranges;
1303 cdllistvalue_cookie = CdlListValue_Magic;
1304 CYGDBG_MEMLEAK_CONSTRUCTOR();
1306 CYG_POSTCONDITION_THISC();
1307 CYG_REPORT_RETURN();
1310 CdlListValue & CdlListValue::operator=(const CdlListValue& original)
1312 CYG_REPORT_FUNCNAME("CdlListValue:: assignment operator");
1313 CYG_REPORT_FUNCARG2XV(this, &original);
1314 CYG_INVARIANT_CLASSOC(CdlListValue, original);
1316 if (this != &original) {
1318 integer_ranges.clear();
1319 double_ranges.clear();
1320 table = original.table;
1321 integer_ranges = original.integer_ranges;
1322 double_ranges = original.double_ranges;
1325 CYG_POSTCONDITION_THISC();
1326 CYG_REPORT_RETURN();
1330 CdlListValue::~CdlListValue()
1332 CYG_REPORT_FUNCNAME("CdlListValue:: destructor");
1333 CYG_REPORT_FUNCARG1XV(this);
1334 CYG_PRECONDITION_THISC();
1336 cdllistvalue_cookie = CdlListValue_Invalid;
1338 integer_ranges.clear();
1339 double_ranges.clear();
1340 CYGDBG_MEMLEAK_DESTRUCTOR();
1342 CYG_REPORT_RETURN();
1345 // ----------------------------------------------------------------------------
1346 // Finding out about the current legal values. These routines can be
1347 // used by GUI-related code to figure out a sensible widget to be used
1348 // for a CDL entity. In nearly all cases life will be simple: either
1349 // there will be a fixed set of legal values and the user merely has
1350 // to choose one of these; or there will be a simple numerical range.
1351 // Occasionally life may be more complicated, if the full generality
1352 // of CDL list expressions is being used, and it will be necessary to
1353 // use an entry box instead. Note that the entity's flavor may also
1354 // affect the user interface.
1356 const std::vector<CdlSimpleValue>&
1357 CdlListValue::get_table(void) const
1359 CYG_REPORT_FUNCNAME("CdlListValue::get_table");
1360 CYG_REPORT_FUNCARG1XV(this);
1361 CYG_PRECONDITION_THISC();
1363 CYG_REPORT_RETURN();
1367 const std::vector<std::pair<cdl_int, cdl_int> >&
1368 CdlListValue::get_integer_ranges(void) const
1370 CYG_REPORT_FUNCNAME("CdlListValue::get_integer_ranges");
1371 CYG_REPORT_FUNCARG1XV(this);
1372 CYG_PRECONDITION_THISC();
1374 CYG_REPORT_RETURN();
1375 return integer_ranges;
1378 const std::vector<std::pair<double, double> >&
1379 CdlListValue::get_double_ranges(void) const
1381 CYG_REPORT_FUNCNAME("CdlListValue::get_double_ranges");
1382 CYG_REPORT_FUNCARG1XV(this);
1383 CYG_PRECONDITION_THISC();
1385 CYG_REPORT_RETURN();
1386 return double_ranges;
1389 // ----------------------------------------------------------------------------
1390 // Membership. This can be quite complicated.
1392 // 1) anything which has an integer representation must be checked against
1393 // the integer ranges and the vector of integer constants. It must
1394 // also be checked against the floating point ranges, since calculations
1395 // may have resulted in the fractional part disappearing, assuming that
1396 // the integer has a floating point representation.
1398 // 2) similarly anything which has a floating point representation must
1399 // be checked against the floating point ranges and constant vector.
1400 // In addition it may have an empty fractional part in which case
1401 // integer comparisons have to be attempted as well.
1403 // 3) string data needs to be tested first of all for integer and double
1404 // representations. If these fail then the comparison should be against
1405 // the string vector.
1407 // For floating point data exact comparisons are of course meaningless,
1408 // and arguably the vector of floating point constants is useless. The
1409 // ranges vector is better, but still not ideal. It may be necessary
1410 // to introduce an epsilon fudge factor.
1413 CdlListValue::is_member(CdlSimpleValue& val) const
1415 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (CdlSimpleValue)", "result %d");
1416 CYG_REPORT_FUNCARG2XV(this, &val);
1417 CYG_PRECONDITION_THISC();
1419 bool result = false;
1420 if (val.has_integer_value()) {
1421 result = is_member(val.get_integer_value(), false);
1423 if (!result && val.has_double_value()) {
1424 result = is_member(val.get_double_value(), false);
1427 result = is_member(val.get_value());
1430 CYG_REPORT_RETVAL(result);
1435 CdlListValue::is_member(std::string val, bool allow_conversions) const
1437 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (string)", "result %d");
1438 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1439 CYG_PRECONDITION_THISC();
1441 bool result = false;
1442 if (allow_conversions) {
1443 cdl_int integer_value;
1444 double double_value;
1446 if (Cdl::string_to_integer(val, integer_value)) {
1447 result = is_member(integer_value, false);
1449 if (!result && Cdl::string_to_double(val, double_value)) {
1450 result = is_member(double_value, false);
1454 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1455 if (val_i->get_value() == val) {
1462 CYG_REPORT_RETVAL(result);
1467 CdlListValue::is_member(cdl_int val, bool allow_conversions) const
1469 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (int)", "result %d");
1470 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1471 CYG_PRECONDITION_THISC();
1473 bool result = false;
1474 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1475 if (val_i->has_integer_value() && (val_i->get_integer_value() == val)) {
1481 for (std::vector<std::pair<cdl_int,cdl_int> >::const_iterator i = integer_ranges.begin();
1482 i != integer_ranges.end(); i++) {
1483 if ((val >= i->first) && (val <= i->second)) {
1489 if (!result && allow_conversions) {
1490 double double_value = Cdl::integer_to_double(val);
1491 result = is_member(double_value, false);
1494 CYG_REPORT_RETVAL(result);
1499 CdlListValue::is_member(double val, bool allow_conversions) const
1501 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (double)", "result %d");
1502 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1503 CYG_PRECONDITION_THISC();
1505 bool result = false;
1506 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1507 if (val_i->has_double_value() && (val_i->get_double_value() == val)) {
1513 for (std::vector<std::pair<double,double> >::const_iterator i = double_ranges.begin();
1514 i != double_ranges.end(); i++) {
1515 if ((val >= i->first) && (val <= i->second)) {
1521 if (!result && allow_conversions) {
1522 cdl_int integer_value;
1523 if (Cdl::double_to_integer(val, integer_value)) {
1524 result = is_member(integer_value, false);
1528 CYG_REPORT_RETVAL(result);
1532 // ----------------------------------------------------------------------------
1535 CdlListValue::check_this(cyg_assert_class_zeal zeal) const
1537 if (CdlListValue_Magic != cdllistvalue_cookie) {
1540 CYGDBG_MEMLEAK_CHECKTHIS();
1542 // After construction the various vectors will still be empty, they
1543 // do not get filled in until a list expression is evaluated. No
1544 // further tests are possible here.
1550 //{{{ dialog property
1552 // ----------------------------------------------------------------------------
1553 // Syntax: dialog <reference>
1556 CdlValuableBody::dialog_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1559 CYG_REPORT_FUNCNAME("CdlValuable::dialog_update_handler");
1560 CYG_PRECONDITION_CLASSC(transaction);
1561 CYG_PRECONDITION_CLASSC(source);
1562 CYG_PRECONDITION_CLASSC(prop);
1564 // The main update of interest is Loaded (iff dest != 0), and
1565 // Created. These updates indicate that the destination now exists,
1566 // so it is possible to check that the destination is a dialog.
1567 if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1568 (CdlUpdate_Created == change)) {
1570 CYG_ASSERT_CLASSC(dest);
1571 CdlDialog dialog = dynamic_cast<CdlDialog>(dest);
1573 std::string msg = dest->get_class_name() + " " + dest->get_name() +
1574 " cannot be used in a dialog property, it is not a custom dialog.";
1575 CdlConflict_DataBody::make(transaction, source, prop, msg);
1578 } else if (CdlUpdate_Destroyed == change) {
1579 // If there was a data conflict object, it is no longer relevant
1580 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1583 CYG_REPORT_RETURN();
1587 CdlValuableBody::parse_dialog(CdlInterpreter interp, int argc, const char* argv[])
1589 CYG_REPORT_FUNCNAMETYPE("parse_dialog", "result %d");
1591 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Dialog, 0, 0, false, &dialog_update_handler);
1593 CYG_REPORT_RETVAL(result);
1598 CdlValuableBody::has_dialog() const
1600 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_dialog", "result %d");
1601 CYG_REPORT_FUNCARG1XV(this);
1602 CYG_PRECONDITION_THISC();
1604 // It is not enough to have the property, the dialog reference must also be
1605 // resolved and go to a dialog.
1606 bool result = false;
1607 CdlProperty property = get_property(CdlPropertyId_Dialog);
1608 if (0 != property) {
1609 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1610 CYG_ASSERTC(0 != ref_prop);
1612 CdlNode destination = ref_prop->get_destination();
1613 if (0 != destination) {
1614 CdlDialog dialog = dynamic_cast<CdlDialog>(destination);
1620 CYG_REPORT_RETVAL(result);
1626 CdlValuableBody::get_dialog() const
1628 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_dialog", "result %p");
1629 CYG_REPORT_FUNCARG1XV(this);
1630 CYG_PRECONDITION_THISC();
1632 CdlDialog result = 0;
1633 CdlProperty property = get_property(CdlPropertyId_Dialog);
1634 if (0 != property) {
1635 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1636 CYG_ASSERTC(0 != ref_prop);
1638 CdlNode destination = ref_prop->get_destination();
1639 if (0 != destination) {
1640 result = dynamic_cast<CdlDialog>(destination);
1644 CYG_REPORT_RETVAL(result);
1649 //{{{ wizard property
1651 // ----------------------------------------------------------------------------
1652 // Syntax: wizard <reference>
1655 CdlValuableBody::wizard_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1658 CYG_REPORT_FUNCNAME("CdlValuable::wizard_update_handler");
1659 CYG_PRECONDITION_CLASSC(transaction);
1660 CYG_PRECONDITION_CLASSC(source);
1661 CYG_PRECONDITION_CLASSC(prop);
1663 // The main update of interest is Loaded (iff dest != 0), and
1664 // Created. These updates indicate that the destination now exists,
1665 // so it is possible to check that the destination is a dialog.
1666 if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1667 (CdlUpdate_Created == change)) {
1669 CYG_ASSERT_CLASSC(dest);
1670 CdlWizard wizard = dynamic_cast<CdlWizard>(dest);
1672 std::string msg = dest->get_class_name() + " " + dest->get_name() +
1673 " cannot be used in a wizard property, it is not a wizard.";
1674 CdlConflict_DataBody::make(transaction, source, prop, msg);
1677 } else if (CdlUpdate_Destroyed == change) {
1678 // If there was a data conflict object, it is no longer relevant
1679 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1682 CYG_REPORT_RETURN();
1686 CdlValuableBody::parse_wizard(CdlInterpreter interp, int argc, const char* argv[])
1688 CYG_REPORT_FUNCNAMETYPE("parse_wizard", "result %d");
1690 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Wizard, 0, 0, false, &wizard_update_handler);
1691 CYG_REPORT_RETVAL(result);
1696 CdlValuableBody::has_wizard() const
1698 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_wizard", "result %d");
1699 CYG_REPORT_FUNCARG1XV(this);
1700 CYG_PRECONDITION_THISC();
1702 // It is not enough to have the property, the wizard reference
1703 // must also be resolved to a wizard object.
1704 bool result = false;
1705 CdlProperty property = get_property(CdlPropertyId_Wizard);
1706 if (0 != property) {
1707 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1708 CYG_ASSERTC(0 != ref_prop);
1710 CdlNode destination = ref_prop->get_destination();
1711 if (0 != destination) {
1712 CdlWizard wizard = dynamic_cast<CdlWizard>(destination);
1713 CYG_ASSERTC(0 != wizard);
1714 CYG_UNUSED_PARAM(CdlWizard, wizard);
1718 CYG_REPORT_RETVAL(result);
1723 CdlValuableBody::get_wizard() const
1725 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_wizard", "result %p");
1726 CYG_REPORT_FUNCARG1XV(this);
1727 CYG_PRECONDITION_THISC();
1729 CdlWizard result = 0;
1730 CdlProperty property = get_property(CdlPropertyId_Wizard);
1731 if (0 != property) {
1732 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1733 CYG_ASSERTC(0 != ref_prop);
1735 CdlNode destination = ref_prop->get_destination();
1736 if (0 != destination) {
1737 result = dynamic_cast<CdlWizard>(destination);
1738 CYG_ASSERTC(0 != result);
1742 CYG_REPORT_RETVAL(result);
1747 //{{{ legal_values property
1749 // ----------------------------------------------------------------------------
1750 // Syntax: legal_values <list expression>
1753 CdlValuableBody::legal_values_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1756 CYG_REPORT_FUNCNAME("legal_values_update_handler");
1758 // Loaded and Unloading are of no immediate interest, reference
1759 // updating happens in the calling code.
1761 // Any other change can affect the list expression and hence
1762 // invalidate the current value.
1763 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1764 CYG_REPORT_RETURN();
1768 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1769 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(prop);
1770 CYG_ASSERT_CLASSC(valuable);
1771 CYG_ASSERT_CLASSC(lexpr);
1773 valuable->check_value(transaction);
1775 CYG_UNUSED_PARAM(CdlNode, dest);
1776 CYG_UNUSED_PARAM(CdlProperty_ListExpression, lexpr);
1777 CYG_REPORT_RETURN();
1781 CdlValuableBody::parse_legal_values(CdlInterpreter interp, int argc, const char* argv[])
1783 CYG_REPORT_FUNCNAMETYPE("parse_legal_values", "result %d");
1785 int result = CdlParse::parse_listexpression_property(interp, argc, argv, CdlPropertyId_LegalValues, 0, 0,
1786 &legal_values_update_handler);
1787 CYG_REPORT_RETVAL(result);
1792 CdlValuableBody::has_legal_values() const
1794 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_legal_values", "result %d");
1795 CYG_REPORT_FUNCARG1XV(this);
1796 CYG_PRECONDITION_THISC();
1798 bool result = has_property(CdlPropertyId_LegalValues);
1799 CYG_REPORT_RETVAL(result);
1803 CdlProperty_ListExpression
1804 CdlValuableBody::get_legal_values() const
1806 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_legal_values", "result %p");
1807 CYG_REPORT_FUNCARG1XV(this);
1808 CYG_PRECONDITION_THISC();
1810 CdlProperty_ListExpression result = 0;
1811 CdlProperty property = get_property(CdlPropertyId_LegalValues);
1812 if (0 != property) {
1813 result = dynamic_cast<CdlProperty_ListExpression>(property);
1814 CYG_ASSERTC(0 != result);
1817 CYG_REPORT_RETVAL(result);
1822 //{{{ default_value property
1824 // ----------------------------------------------------------------------------
1825 // syntax: default_value <expr>
1828 CdlValuableBody::default_value_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1831 CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1832 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1834 // Loaded and unloading should be ignored.
1835 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1836 CYG_REPORT_RETURN();
1840 // Init, Created, Destroyed, ValueChange and ActiveChange should
1841 // all result in the expression being re-evaluated and the result
1843 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1844 CYG_ASSERTC(0 != valuable);
1845 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1846 CYG_ASSERTC(0 != expr);
1852 CdlEvalContext context(transaction, source, prop);
1853 expr->eval(context, val);
1855 valuable->set(transaction, val, CdlValueSource_Default);
1857 } catch(CdlEvalException e) {
1860 // An EvalException conflict will have been created, so the
1861 // user knows that this default_value is not kosher. It is
1862 // still a good idea to make sure that the object retains a
1865 valuable->set(transaction, val, CdlValueSource_Default);
1868 CYG_UNUSED_PARAM(CdlNode, dest);
1869 CYG_REPORT_RETURN();
1873 CdlValuableBody::parse_default_value(CdlInterpreter interp, int argc, const char* argv[])
1875 CYG_REPORT_FUNCNAMETYPE("parse_default_value", "result %d");
1876 int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_DefaultValue, 0, 0,
1877 &default_value_update_handler);
1878 CYG_REPORT_RETVAL(result);
1883 CdlValuableBody::has_default_value_expression() const
1885 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_default_value_expression", "result %d");
1886 CYG_REPORT_FUNCARG1XV(this);
1887 CYG_PRECONDITION_THISC();
1889 bool result = has_property(CdlPropertyId_DefaultValue);
1890 CYG_REPORT_RETVAL(result);
1894 CdlProperty_Expression
1895 CdlValuableBody::get_default_value_expression() const
1897 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_default_value_expression", "result %");
1898 CYG_REPORT_FUNCARG1XV(this);
1899 CYG_PRECONDITION_THISC();
1901 CdlProperty_Expression result = 0;
1902 CdlProperty property = get_property(CdlPropertyId_DefaultValue);
1903 if (0 != property) {
1904 result = dynamic_cast<CdlProperty_Expression>(property);
1905 CYG_ASSERTC(0 != result);
1908 CYG_REPORT_RETVAL(result);
1913 //{{{ calculated_property
1915 // ----------------------------------------------------------------------------
1916 // Syntax: calculated <expression>
1919 CdlValuableBody::calculated_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1922 CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1923 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1925 // Loaded and unloading should be ignored.
1926 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1927 CYG_REPORT_RETURN();
1931 // Init, Created, Destroyed, ValueChange and ActiveChange should
1932 // all result in the expression being re-evaluated and the result
1934 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1935 CYG_ASSERTC(0 != valuable);
1936 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1937 CYG_ASSERTC(0 != expr);
1943 CdlEvalContext context(transaction, source, prop);
1944 expr->eval(context, val);
1946 valuable->set(transaction, val, CdlValueSource_Default);
1948 } catch(CdlEvalException e) {
1951 // An EvalException conflict will have been created, so the
1952 // user knows that this default_value is not kosher. It is
1953 // still a good idea to make sure that the object retains a
1956 valuable->set(transaction, val, CdlValueSource_Default);
1959 CYG_UNUSED_PARAM(CdlNode, dest);
1960 CYG_REPORT_RETURN();
1963 // FIXME: check for flavor none?
1965 CdlValuableBody::parse_calculated(CdlInterpreter interp, int argc, const char* argv[])
1967 CYG_REPORT_FUNCNAMETYPE("parse_calculated", "result %d");
1969 int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_Calculated, 0, 0,
1970 &calculated_update_handler);
1971 CYG_REPORT_RETVAL(result);
1976 CdlValuableBody::has_calculated_expression() const
1978 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_calculated_expression", "result %d");
1979 CYG_REPORT_FUNCARG1XV(this);
1980 CYG_PRECONDITION_THISC();
1982 bool result = has_property(CdlPropertyId_Calculated);
1983 CYG_REPORT_RETVAL(result);
1987 CdlProperty_Expression
1988 CdlValuableBody::get_calculated_expression() const
1990 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_calculated_expression", "result %p");
1991 CYG_REPORT_FUNCARG1XV(this);
1992 CYG_PRECONDITION_THISC();
1994 CdlProperty_Expression result = 0;
1995 CdlProperty property = get_property(CdlPropertyId_Calculated);
1996 if (0 != property) {
1997 result = dynamic_cast<CdlProperty_Expression>(property);
1998 CYG_ASSERTC(0 != result);
2001 CYG_REPORT_RETVAL(result);
2006 //{{{ active_if property
2008 // ----------------------------------------------------------------------------
2010 // active_if <goal expression>
2013 CdlValuableBody::active_if_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2016 CYG_REPORT_FUNCNAME("CdlValuable::active_if_update_handler");
2017 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2018 CYG_PRECONDITION_CLASSC(transaction);
2019 CYG_PRECONDITION_CLASSC(source);
2020 CYG_PRECONDITION_CLASSC(prop);
2022 // Loaded should be ignored here, the world is still getting sorted out.
2023 // Unloading is of no interest, the source is disappearing anyway.
2024 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2025 CYG_REPORT_RETURN();
2029 // Any other change warrants re-evaluating the active status of the source.
2030 // This can be achieved via a test_active() call, although that may do
2031 // more work than is strictly necessary e.g. it may re-evaluate other
2032 // is_active properties. In practice it is unlikely that there will
2033 // be enough other constraints to warrant more efficient processing.
2034 bool old_state = transaction->is_active(source);
2035 bool new_state = source->test_active(transaction);
2036 if (old_state != new_state) {
2037 transaction->set_active(source, new_state);
2040 CYG_UNUSED_PARAM(CdlNode, dest);
2041 CYG_REPORT_RETURN();
2045 CdlValuableBody::parse_active_if(CdlInterpreter interp, int argc, const char* argv[])
2047 CYG_REPORT_FUNCNAMETYPE("parse_active_if", "result %d");
2049 int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_ActiveIf, 0, 0,
2050 &active_if_update_handler);
2051 CYG_REPORT_RETVAL(result);
2056 CdlValuableBody::has_active_if_conditions() const
2058 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_active_if_conditions", "result %d");
2059 CYG_REPORT_FUNCARG1XV(this);
2060 CYG_PRECONDITION_THISC();
2062 bool result = has_property(CdlPropertyId_ActiveIf);
2063 CYG_REPORT_RETVAL(result);
2068 CdlValuableBody::get_active_if_conditions(std::vector<CdlProperty_GoalExpression>& result) const
2070 CYG_REPORT_FUNCNAME("CdlValuable::get_active_if_conditions");
2071 CYG_REPORT_FUNCARG1XV(this);
2072 CYG_PRECONDITION_THISC();
2074 std::vector<CdlProperty> properties;
2075 get_properties(CdlPropertyId_ActiveIf, properties);
2076 std::vector<CdlProperty>::const_iterator i;
2077 for (i = properties.begin(); i != properties.end(); i++) {
2078 CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2079 CYG_ASSERTC(0 != goal);
2080 result.push_back(goal);
2083 CYG_REPORT_RETURN();
2087 //{{{ requires property
2089 // ----------------------------------------------------------------------------
2090 // Syntax: requires <goal expression>
2093 CdlValuableBody::requires_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2096 CYG_REPORT_FUNCNAME("CdlValuable::requires_update_handler");
2097 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2098 CYG_PRECONDITION_CLASSC(transaction);
2100 // Loaded and Unloading are not of interest.
2101 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2102 CYG_REPORT_RETURN();
2106 // Any other change should cause normal handling. This happens in
2107 // a separate function because "requires" properties also need to
2108 // be checked when e.g. the source becomes inactive.
2109 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
2110 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(prop);
2111 CYG_ASSERT_CLASSC(valuable);
2112 CYG_ASSERT_CLASSC(gexpr);
2114 valuable->check_requires(transaction, gexpr);
2116 CYG_UNUSED_PARAM(CdlNode, dest);
2117 CYG_REPORT_RETURN();
2121 CdlValuableBody::parse_requires(CdlInterpreter interp, int argc, const char* argv[])
2123 CYG_REPORT_FUNCNAMETYPE("parse_requires", "result %d");
2125 int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_Requires, 0, 0,
2126 &requires_update_handler);
2127 CYG_REPORT_RETVAL(result);
2132 CdlValuableBody::has_requires_goals() const
2134 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_requires_goals", "result %d");
2135 CYG_REPORT_FUNCARG1XV(this);
2136 CYG_PRECONDITION_THISC();
2138 bool result = has_property(CdlPropertyId_Requires);
2139 CYG_REPORT_RETVAL(result);
2144 CdlValuableBody::get_requires_goals(std::vector<CdlProperty_GoalExpression>& result) const
2146 CYG_REPORT_FUNCNAME("CdlValuable::get_requires_goals");
2147 CYG_REPORT_FUNCARG1XV(this);
2148 CYG_PRECONDITION_THISC();
2150 std::vector<CdlProperty> properties;
2151 get_properties(CdlPropertyId_Requires, properties);
2152 std::vector<CdlProperty>::const_iterator i;
2153 for (i = properties.begin(); i != properties.end(); i++) {
2154 CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2155 CYG_ASSERTC(0 != goal);
2156 result.push_back(goal);
2159 CYG_REPORT_RETURN();
2163 //{{{ implements property
2165 // ----------------------------------------------------------------------------
2166 // Syntax: implements <reference to interface>
2169 CdlValuableBody::implements_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2172 CYG_REPORT_FUNCNAME("CdlValuable::implements_update_handler");
2173 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2174 CYG_PRECONDITION_CLASSC(transaction);
2176 // Calculation of interface values happens inside
2177 // CdlInterfaceBody::recalculate(). That member function simply
2178 // checks all of the implementors and recalculates the value from
2179 // scratch. It needs to be invoked whenever there is a relevant
2180 // change to the implementors. Currently no attempt is made to
2181 // optimise interface updates, although this may have to change in
2184 // Any changes to the interface itself can be ignored.
2185 if ((CdlUpdate_ValueChange == change) || (CdlUpdate_ActiveChange == change)) {
2186 CYG_REPORT_RETURN();
2190 // The second stage init is irrelevant
2191 if (CdlUpdate_Init == change) {
2192 CYG_REPORT_RETURN();
2197 // 1) source is being loaded, dest valid
2198 // 2) source is being loaded, dest unknown
2199 // 3) source is being unloaded, dest valid
2200 // 4) source is being unloaded, dest unknown
2201 // 5) dest has been created
2202 // 6) dest is going away
2204 // If we have a valid dest, it needs to be updated and any structural
2205 // conflicts have to be cleared.
2207 // If there is no dest, the implements property remains unbound.
2208 // A suitable conflict is created in the base class.
2210 // If the dest is invalid, a structural conflict has to be created.
2211 if (CdlUpdate_Destroyed == change) {
2212 // There is no need to do any clean-ups in the dest.
2216 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2218 CdlInterface interface = dynamic_cast<CdlInterface>(dest);
2220 if (0 == interface) {
2221 std::string msg = source->get_class_name() + " " + source->get_name() + " cannot implement " +
2222 dest->get_name() + "\n The latter is not an interface.";
2223 CdlConflict_DataBody::make(transaction, source, prop, msg);
2225 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2226 interface->recalculate(transaction);
2230 CYG_REPORT_RETURN();
2234 CdlValuableBody::parse_implements(CdlInterpreter interp, int argc, const char* argv[])
2236 CYG_REPORT_FUNCNAMETYPE("parse_implements", "result %d");
2238 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Implements, 0, 0, false,
2239 &implements_update_handler);
2241 CYG_REPORT_RETVAL(result);
2246 CdlValuableBody::get_implemented_interfaces(std::vector<CdlInterface>& result) const
2248 CYG_REPORT_FUNCNAME("CdlValuable::get_implemented_interfaces");
2249 CYG_REPORT_FUNCARG1XV(this);
2250 CYG_PRECONDITION_THISC();
2252 std::vector<CdlProperty> properties;
2253 get_properties(CdlPropertyId_Implements, properties);
2254 std::vector<CdlProperty>::const_iterator i;
2255 for (i = properties.begin(); i != properties.end(); i++) {
2256 CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*i);
2257 CYG_ASSERTC(0 != refprop);
2258 CdlNode node = refprop->get_destination();
2260 CdlInterface interface = dynamic_cast<CdlInterface>(node);
2261 CYG_ASSERT_CLASSC(interface);
2262 result.push_back(interface);
2266 CYG_REPORT_RETURN();
2270 //{{{ Other properties
2272 // ----------------------------------------------------------------------------
2273 // Syntax: flavor <legal flavor>
2276 parse_flavor_final_check(CdlInterpreter interp, CdlProperty_String prop)
2278 CYG_REPORT_FUNCNAME("parse_flavor_final_check");
2279 CYG_PRECONDITION_CLASSC(interp);
2280 CYG_PRECONDITION_CLASSC(prop);
2282 const std::string& str = prop->get_string();
2283 std::string copy = std::string(str);
2284 CdlValueFlavor flavor;
2286 if (!Cdl::string_to_flavor(copy, flavor)) {
2287 CdlParse::report_property_parse_error(interp, prop, str + " is not a valid CDL flavor.");
2290 CYG_REPORT_RETURN();
2295 CdlValuableBody::parse_flavor(CdlInterpreter interp, int argc, const char* argv[])
2297 CYG_REPORT_FUNCNAMETYPE("parse_flavor", "result %d");
2299 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Flavor, 0, &parse_flavor_final_check);
2300 CYG_REPORT_RETVAL(result);
2304 // ----------------------------------------------------------------------------
2305 // syntax: group <group name>
2307 CdlValuableBody::parse_group(CdlInterpreter interp, int argc, const char* argv[])
2309 CYG_REPORT_FUNCNAMETYPE("parse_group", "result %d");
2311 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Group, 0, 0);
2313 CYG_REPORT_RETVAL(result);
2317 // ----------------------------------------------------------------------------
2318 // Syntax: check_proc <tclcode>
2321 CdlValuableBody::parse_check_proc(CdlInterpreter interp, int argc, const char* argv[])
2323 CYG_REPORT_FUNCNAMETYPE("parse_check_proc", "result %d");
2325 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_CheckProc, 0, 0);
2327 CYG_REPORT_RETVAL(result);
2332 CdlValuableBody::has_check_proc() const
2334 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_check_proc", "result %d");
2335 CYG_REPORT_FUNCARG1XV(this);
2336 CYG_PRECONDITION_THISC();
2338 bool result = has_property(CdlPropertyId_CheckProc);
2339 CYG_REPORT_RETVAL(result);
2344 CdlValuableBody::get_check_proc() const
2346 CYG_REPORT_FUNCNAME("CdlValuable::get_check_proc");
2347 CYG_REPORT_FUNCARG1XV(this);
2348 CYG_PRECONDITION_THISC();
2350 cdl_tcl_code result = "";
2351 CdlProperty property = get_property(CdlPropertyId_CheckProc);
2352 if (0 != property) {
2353 CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2354 CYG_ASSERTC(0 != code_prop);
2355 result = code_prop->get_code();
2358 CYG_REPORT_RETURN();
2362 // ----------------------------------------------------------------------------
2363 // Syntax: entry_proc <tclcode>
2366 CdlValuableBody::parse_entry_proc(CdlInterpreter interp, int argc, const char* argv[])
2368 CYG_REPORT_FUNCNAMETYPE("parse_entry_proc", "result %d");
2370 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_EntryProc, 0, 0);
2372 CYG_REPORT_RETVAL(result);
2377 CdlValuableBody::has_entry_proc() const
2379 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_entry_proc", "result %d");
2380 CYG_REPORT_FUNCARG1XV(this);
2381 CYG_PRECONDITION_THISC();
2383 bool result = has_property(CdlPropertyId_EntryProc);
2384 CYG_REPORT_RETVAL(result);
2388 CdlValuableBody::get_entry_proc() const
2390 CYG_REPORT_FUNCNAME("CdlValuable::get_entry_proc");
2391 CYG_REPORT_FUNCARG1XV(this);
2392 CYG_PRECONDITION_THISC();
2394 cdl_tcl_code result = "";
2395 CdlProperty property = get_property(CdlPropertyId_EntryProc);
2396 if (0 != property) {
2397 CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2398 CYG_ASSERTC(0 != code_prop);
2399 result = code_prop->get_code();
2402 CYG_REPORT_RETURN();
2408 //{{{ CdlValuable misc
2410 // ----------------------------------------------------------------------------
2411 // Objects with flavor none are not modifiable. Also, objects with the
2412 // calculated property are not modifiable. Everything else is ok.
2415 CdlValuableBody::is_modifiable() const
2417 CYG_REPORT_FUNCNAMETYPE("CdlValuableBody::is_modifiable", "result %d");
2418 CYG_REPORT_FUNCARG1XV(this);
2419 CYG_PRECONDITION_THISC();
2422 if (CdlValueFlavor_None == get_flavor()) {
2424 } else if (has_property(CdlPropertyId_Calculated)) {
2428 CYG_REPORT_RETVAL(result);
2433 //{{{ CdlValuable::get_widget_hint()
2435 // ----------------------------------------------------------------------------
2438 CdlValuableBody::get_widget_hint(CdlWidgetHint& hint)
2440 CYG_REPORT_FUNCNAME("CdlValuable::get_widget_hint");
2441 CYG_REPORT_FUNCARG2XV(this, &hint);
2442 CYG_PRECONDITION_THISC();
2444 // Start by resetting the hint to default values.
2445 hint.bool_widget = CdlBoolWidget_None;
2446 hint.value_widget = CdlValueWidget_None;
2447 hint.radio_button_interface = "";
2449 // If the valuable is a loadable then it cannot be modified directly.
2450 // Changing the value means unloading and/or loading more data
2451 // into the configuration. This should always be handled via a
2452 // separate dialog, followed by a tree redisplay
2453 CdlConstLoadable loadable = dynamic_cast<CdlConstLoadable>(this);
2454 if (0 != loadable) {
2455 hint.value_widget = CdlValueWidget_Loadable;
2456 CYG_REPORT_RETURN();
2460 // If the valuable is not modifiable then we are already done.
2461 CdlValueFlavor flavor = this->get_flavor();
2462 if ((CdlValueFlavor_None == flavor) || !this->is_modifiable()) {
2463 CYG_REPORT_RETURN();
2467 // If there is a custom dialog and dialogs are enabled, use it.
2468 if (this->has_dialog() && CdlDialogBody::dialogs_are_enabled()) {
2469 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2470 hint.bool_widget = CdlBoolWidget_CustomDialog;
2472 if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2473 hint.value_widget = CdlValueWidget_CustomDialog;
2475 CYG_REPORT_RETURN();
2479 // Process the bool part, if any
2480 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2482 // Default to a CheckButton
2483 hint.bool_widget = CdlBoolWidget_CheckButton;
2485 // Under some circumstances it is appropriate to use a radio button instead.
2486 // This is the case when there are several mutually exclusive entities.
2487 // Most of the time radio buttons should actually be handled by a single
2488 // option which has a list of legal values. There are a couple of cases
2489 // where this is not appropriate:
2491 // 1) grouping. Some of the mutually exclusive entities could be containers.
2492 // With clever use of a single option and some active_if properties it
2493 // would be possible to get almost the same effect, but not quite.
2495 // 2) external packages. It should be possible to have a third party package
2496 // which could add e.g. a new scheduler.
2498 // The implementation of this involves interfaces. Basically mutually
2499 // exclusive entities should implement the same interface, and that
2500 // interface should have an explicit requires $cdl_value == 1
2501 // In addition all of the options involved should have the same parent.
2502 // An entity may implement multiple interfaces, so they all have to be checked
2503 CdlInterface radio_interface = 0;
2504 std::vector<CdlProperty> implements = this->get_properties(CdlPropertyId_Implements);
2505 std::vector<CdlProperty>::const_iterator imp_i;
2506 for (imp_i = implements.begin(); (imp_i != implements.end()) && (0 == radio_interface); imp_i++) {
2507 CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*imp_i);
2508 CYG_ASSERT_CLASSC(refprop);
2510 CdlNode destnode = refprop->get_destination();
2511 if (0 == destnode) {
2514 CdlInterface interface = dynamic_cast<CdlInterface>(destnode);
2515 CYG_ASSERT_CLASSC(interface);
2517 std::vector<CdlProperty_GoalExpression> requires;
2518 std::vector<CdlProperty_GoalExpression>::const_iterator req_i;
2519 interface->get_requires_goals(requires);
2520 for (req_i = requires.begin(); req_i != requires.end(); req_i++) {
2522 CdlExpression expr = (*req_i)->get_expression();
2523 CdlSubexpression& subexpr = expr->sub_expressions[expr->first_subexpression];
2524 if (CdlExprOp_Equal != subexpr.op) {
2528 CdlSubexpression& lhs = expr->sub_expressions[subexpr.lhs_index];
2529 CdlSubexpression& rhs = expr->sub_expressions[subexpr.rhs_index];
2530 CdlSubexpression* ref_operand = &lhs;
2532 // Allow for "a == 1" or "1 == a"
2533 if ((CdlExprOp_IntegerConstant == lhs.op) && (1 == lhs.constants.get_integer_value())) {
2535 } else if ((CdlExprOp_IntegerConstant == rhs.op) && (1 == rhs.constants.get_integer_value())) {
2541 if (CdlExprOp_Reference != ref_operand->op) {
2544 CdlReference& ref = expr->references[ref_operand->reference_index];
2545 if (ref.get_destination() == interface) {
2549 if (req_i == requires.end()) {
2553 CdlContainer parent = this->get_parent();
2554 CYG_ASSERT_CLASSC(parent);
2556 std::vector<CdlValuable> implementers;
2557 std::vector<CdlValuable>::const_iterator imp_i;
2558 interface->get_implementers(implementers);
2559 for (imp_i = implementers.begin(); imp_i != implementers.end(); imp_i++) {
2560 if (parent != (*imp_i)->get_parent()) {
2565 if (imp_i == implementers.end()) {
2566 // An interface has been found that matches the constraints.
2567 radio_interface = interface;
2570 if (0 != radio_interface) {
2571 hint.bool_widget = CdlBoolWidget_Radio;
2572 hint.radio_button_interface = radio_interface->get_name();
2576 // Process the data part, if any
2577 if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2579 // Default to a simple entry box.
2580 hint.value_widget = CdlValueWidget_EntryBox;
2582 // If there is a legal_values list, this will normally indicate
2583 // which widget should be used.
2584 if (this->has_legal_values()) {
2585 // The legal_values expression needs to be evaluated and examined.
2586 // If the result is a simple numerical range then all we need to
2587 // figure out is whether to default to decimal, hex, octal or double.
2588 // Otherwise if the result is a simple list and all of the entries
2589 // are numerical, that is sufficient information. If a list with
2590 // non-numerical entries that is fine as well. Anything more complicated
2591 // needs to revert to an entry box.
2592 CdlProperty_ListExpression lexpr = this->get_legal_values();
2593 CdlEvalContext context(0, this, lexpr);
2597 lexpr->eval(context, val);
2598 const std::vector<CdlSimpleValue>& table = val.get_table();
2599 const std::vector<std::pair<cdl_int, cdl_int> >& int_ranges = val.get_integer_ranges();
2600 const std::vector<std::pair<double, double> >& double_ranges = val.get_double_ranges();
2602 if ((0 == table.size()) && (0 == int_ranges.size()) && (1 == double_ranges.size())) {
2604 // A straightforward range of double precision numbers
2605 hint.value_widget = CdlValueWidget_DoubleRange;
2607 } else if ((0 == table.size()) && (1 == int_ranges.size()) && (0 == double_ranges.size())) {
2609 // Bummer. The formatting information has been lost.
2610 // To fix this the two sets of ranges should be collapsed into pairs of
2611 // CdlSimpleValue's.
2612 hint.value_widget = CdlValueWidget_DecimalRange;
2614 } else if ((1 <= table.size() && (0 == int_ranges.size()) && (0 == double_ranges.size()))) {
2616 // If all of the values are numerical, then we have a numeric set.
2617 // Otherwise we have a string set.
2618 bool all_numeric = true;
2619 std::vector<CdlSimpleValue>::const_iterator tab_i;
2620 for (tab_i = table.begin(); (tab_i != table.end()) && all_numeric; tab_i++) {
2621 if (!tab_i->has_double_value() && !tab_i->has_integer_value()) {
2622 all_numeric = false;
2626 hint.value_widget = CdlValueWidget_NumericSet;
2628 hint.value_widget = CdlValueWidget_StringSet;
2632 // The list expression is a complex combination. Leave it as an entry box.
2633 // In some cases it would be possible to do better, for example
2634 // legal_values -1 1 to 4 8 to 12
2635 // Support for cases like these may get added in future, if such cases
2636 // ever arise in practice.
2640 // Not a lot that can be done here, unfortunately
2643 // There is no legal_values property, so an entry box is probably the
2644 // right thing to use. There is a special case for multiline strings,
2645 // identified by a default_value expression that contains a newline.
2646 if (this->has_default_value_expression()) {
2647 CdlProperty_Expression expr = this->get_default_value_expression();
2648 CdlEvalContext context(0, this, expr);
2651 expr->eval(context, val);
2652 std::string tmp = val.get_value();
2653 if (std::string::npos != tmp.find('\n')) {
2654 hint.value_widget = CdlValueWidget_MultilineString;
2657 // Not a lot that can be done here, unfortunately
2663 CYG_REPORT_RETURN();
2667 //{{{ CdlValuable get operations
2669 // ----------------------------------------------------------------------------
2671 CdlValuableBody::get_whole_value() const
2673 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_whole_value", "result %p");
2674 CYG_REPORT_FUNCARG1XV(this);
2675 CYG_PRECONDITION_THISC();
2677 CYG_REPORT_RETVAL(&value);
2682 CdlValuableBody::get_flavor() const
2684 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_flavor", "result %d");
2685 CYG_REPORT_FUNCARG1XV(this);
2686 CYG_PRECONDITION_THISC();
2688 CdlValueFlavor result = value.get_flavor();
2689 CYG_REPORT_RETVAL((int) result);
2694 CdlValuableBody::get_source() const
2696 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2697 CYG_REPORT_FUNCARG1XV(this);
2698 CYG_PRECONDITION_THISC();
2700 CdlValueSource result = value.get_source();
2701 CYG_REPORT_RETVAL((int) result);
2706 CdlValuableBody::has_source(CdlValueSource source) const
2708 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2709 CYG_REPORT_FUNCARG2XV(this, source);
2710 CYG_PRECONDITION_THISC();
2712 bool result = value.has_source(source);
2713 CYG_REPORT_RETVAL(result);
2718 CdlValuableBody::is_enabled(CdlValueSource source) const
2720 CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2721 CYG_REPORT_FUNCARG2XV(this, source);
2722 CYG_PRECONDITION_THISC();
2724 bool result = value.is_enabled(source);
2725 CYG_REPORT_RETVAL(result);
2730 CdlValuableBody::get_value(CdlValueSource source) const
2732 CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2733 CYG_REPORT_FUNCARG2XV(this, source);
2734 CYG_PRECONDITION_THISC();
2736 std::string result = value.get_value(source);
2737 CYG_REPORT_RETURN();
2742 CdlValuableBody::has_integer_value(CdlValueSource source) const
2744 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2745 CYG_REPORT_FUNCARG2XV(this, source);
2746 CYG_PRECONDITION_THISC();
2748 bool result = value.has_integer_value(source);
2749 CYG_REPORT_RETVAL(result);
2754 CdlValuableBody::get_integer_value(CdlValueSource source) const
2756 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2757 CYG_REPORT_FUNCARG2XV(this, source);
2758 CYG_PRECONDITION_THISC();
2760 cdl_int result = value.get_integer_value(source);
2761 CYG_REPORT_RETVAL((int) result);
2766 CdlValuableBody::has_double_value(CdlValueSource source) const
2768 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2769 CYG_REPORT_FUNCARG2XV(this, source);
2770 CYG_PRECONDITION_THISC();
2772 bool result = value.has_double_value(source);
2773 CYG_REPORT_RETVAL(result);
2778 CdlValuableBody::get_double_value(CdlValueSource source) const
2780 CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2781 CYG_REPORT_FUNCARG2XV(this, source);
2782 CYG_PRECONDITION_THISC();
2784 double result = value.get_double_value();
2785 CYG_REPORT_RETURN();
2790 CdlValuableBody::get_simple_value(CdlValueSource source) const
2792 CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2793 CYG_REPORT_FUNCARG2XV(this, source);
2794 CYG_PRECONDITION_THISC();
2796 CdlSimpleValue result = value.get_simple_value(source);
2797 CYG_REPORT_RETURN();
2801 // ----------------------------------------------------------------------------
2803 CdlValuableBody::get_source(CdlTransaction transaction) const
2805 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2806 CYG_REPORT_FUNCARG2XV(this, transaction);
2807 CYG_PRECONDITION_THISC();
2808 CYG_PRECONDITION_CLASSC(transaction);
2810 const CdlValue& transaction_value = transaction->get_whole_value(this);
2811 CdlValueSource result = transaction_value.get_source();
2812 CYG_REPORT_RETVAL((int) result);
2817 CdlValuableBody::has_source(CdlTransaction transaction, CdlValueSource source) const
2819 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2820 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2821 CYG_PRECONDITION_THISC();
2822 CYG_PRECONDITION_CLASSC(transaction);
2824 const CdlValue& transaction_value = transaction->get_whole_value(this);
2825 bool result = transaction_value.has_source(source);
2826 CYG_REPORT_RETVAL(result);
2831 CdlValuableBody::is_enabled(CdlTransaction transaction, CdlValueSource source) const
2833 CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2834 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2835 CYG_PRECONDITION_THISC();
2836 CYG_PRECONDITION_CLASSC(transaction);
2838 const CdlValue& transaction_value = transaction->get_whole_value(this);
2839 bool result = transaction_value.is_enabled(source);
2840 CYG_REPORT_RETVAL(result);
2845 CdlValuableBody::get_value(CdlTransaction transaction, CdlValueSource source) const
2847 CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2848 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2849 CYG_PRECONDITION_THISC();
2850 CYG_PRECONDITION_CLASSC(transaction);
2852 const CdlValue& transaction_value = transaction->get_whole_value(this);
2853 std::string result = transaction_value.get_value(source);
2854 CYG_REPORT_RETURN();
2859 CdlValuableBody::has_integer_value(CdlTransaction transaction, CdlValueSource source) const
2861 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2862 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2863 CYG_PRECONDITION_THISC();
2864 CYG_PRECONDITION_CLASSC(transaction);
2866 const CdlValue& transaction_value = transaction->get_whole_value(this);
2867 bool result = transaction_value.has_integer_value(source);
2868 CYG_REPORT_RETVAL(result);
2873 CdlValuableBody::get_integer_value(CdlTransaction transaction, CdlValueSource source) const
2875 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2876 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2877 CYG_PRECONDITION_THISC();
2878 CYG_PRECONDITION_CLASSC(transaction);
2880 const CdlValue& transaction_value = transaction->get_whole_value(this);
2881 cdl_int result = transaction_value.get_integer_value(source);
2882 CYG_REPORT_RETVAL((int) result);
2887 CdlValuableBody::has_double_value(CdlTransaction transaction, CdlValueSource source) const
2889 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2890 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2891 CYG_PRECONDITION_THISC();
2892 CYG_PRECONDITION_CLASSC(transaction);
2894 const CdlValue& transaction_value = transaction->get_whole_value(this);
2895 bool result = transaction_value.has_double_value(source);
2896 CYG_REPORT_RETVAL(result);
2901 CdlValuableBody::get_double_value(CdlTransaction transaction, CdlValueSource source) const
2903 CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2904 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2905 CYG_PRECONDITION_THISC();
2906 CYG_PRECONDITION_CLASSC(transaction);
2908 const CdlValue& transaction_value = transaction->get_whole_value(this);
2909 double result = transaction_value.get_double_value();
2910 CYG_REPORT_RETURN();
2915 CdlValuableBody::get_simple_value(CdlTransaction transaction, CdlValueSource source) const
2917 CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2918 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2919 CYG_PRECONDITION_THISC();
2920 CYG_PRECONDITION_CLASSC(transaction);
2922 const CdlValue& transaction_value = transaction->get_whole_value(this);
2923 CdlSimpleValue result = transaction_value.get_simple_value(source);
2924 CYG_REPORT_RETURN();
2929 //{{{ CdlValuable internal modify ops
2931 // ----------------------------------------------------------------------------
2932 // There has been a change to either the value itself or to the
2933 // set of legal values. It is necessary to validate the current
2934 // value, maintaining a suitable conflict object.
2936 CdlValuableBody::check_value(CdlTransaction transaction)
2938 CYG_REPORT_FUNCNAME("CdlValuable::check_value");
2939 CYG_REPORT_FUNCARG2XV(this, transaction);
2940 CYG_PRECONDITION_THISC();
2941 CYG_PRECONDITION_CLASSC(transaction);
2943 // Checking the value only makes sense for BoolData and Data
2945 CdlValueFlavor flavor = value.get_flavor();
2946 if ((CdlValueFlavor_BoolData != flavor) && (CdlValueFlavor_Data != flavor)) {
2947 CYG_REPORT_RETURN();
2951 // If the valuable is not currently active and enabled then it
2952 // does not matter whether or not the value is legal. Any old
2953 // conflicts should be destroyed.
2954 if (!(transaction->is_active(this) && this->is_enabled(transaction))) {
2955 transaction->clear_conflicts(this, &CdlConflict_IllegalValueBody::test);
2956 CYG_REPORT_RETURN();
2960 // If there is a legal_values property, check membership.
2961 if (this->has_property(CdlPropertyId_LegalValues)) {
2962 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(get_property(CdlPropertyId_LegalValues));
2963 CYG_ASSERT_CLASSC(lexpr);
2965 CdlSimpleValue val = this->get_simple_value(transaction);
2966 CdlEvalContext context(transaction, this, lexpr);
2968 if (!lexpr->is_member(context, val)) {
2969 if (!transaction->has_conflict(this, lexpr, &CdlConflict_IllegalValueBody::test)) {
2970 CdlConflict_IllegalValueBody::make(transaction, this, lexpr);
2974 // Tne current value is legal. Get rid of any old conflicts.
2975 transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2977 } catch(CdlEvalException e) {
2978 // There should now be an EvalException conflict for this
2979 // node, so there is no point in having an IllegalValue conflict
2981 transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2984 // FIXME: add support for check_proc
2987 CYG_REPORT_RETURN();
2990 // ----------------------------------------------------------------------------
2991 // There has been a change that may affect "requires" properties.
2992 // Again do the necessary checking and maintain suitable conflict
2995 CdlValuableBody::check_requires(CdlTransaction transaction)
2997 CYG_REPORT_FUNCNAME("CdlValuable::check_requires");
2998 CYG_REPORT_FUNCARG2XV(this, transaction);
2999 CYG_PRECONDITION_THISC();
3000 CYG_PRECONDITION_CLASSC(transaction);
3002 std::vector<CdlProperty> requires_properties;
3003 std::vector<CdlProperty>::const_iterator prop_i;
3004 get_properties(CdlPropertyId_Requires, requires_properties);
3005 for (prop_i = requires_properties.begin(); prop_i != requires_properties.end(); prop_i++) {
3007 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3008 CYG_ASSERT_CLASSC(gexpr);
3009 this->check_requires(transaction, gexpr);
3012 CYG_REPORT_RETURN();
3016 CdlValuableBody::check_requires(CdlTransaction transaction, CdlProperty_GoalExpression gexpr)
3018 CYG_REPORT_FUNCNAME("CdlValuable::check_requires (property)");
3019 CYG_REPORT_FUNCARG3XV(this, transaction, gexpr);
3020 CYG_PRECONDITION_THISC();
3021 CYG_PRECONDITION_CLASSC(transaction);
3022 CYG_ASSERT_CLASSC(gexpr);
3024 // If the valuable is not currently active and enabled then the "requires"
3025 // properties are irrelevant, and any old conflicts should be destroyed.
3026 if (!transaction->is_active(this) || !this->is_enabled(transaction)) {
3027 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3028 CYG_REPORT_RETURN();
3032 // What is the current value of the goal expression?
3034 CdlEvalContext context(transaction, this, gexpr);
3035 if (gexpr->eval(context)) {
3036 // The goal is satisfied.
3037 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3039 // The goal is not satisfied. Make sure there is a conflict object.
3040 if (!transaction->has_conflict(this, gexpr, &CdlConflict_RequiresBody::test)) {
3041 CdlConflict_RequiresBody::make(transaction, this, gexpr);
3044 } catch(CdlEvalException e) {
3045 // There should now be an EvalException conflict associated with this node,
3046 // having a requires conflict as well serves no purpose
3047 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3050 CYG_REPORT_RETURN();
3053 // ----------------------------------------------------------------------------
3054 // The update handler. If there is a change to the value or active state
3055 // then it is necessary to reevaluate any requires properties, and to
3056 // check whether or not the value is legal wrt legal_values etc.
3058 CdlValuableBody::update(CdlTransaction transaction, CdlUpdate update)
3060 CYG_REPORT_FUNCNAME("CdlValuable::update");
3061 CYG_REPORT_FUNCARG3XV(this, transaction, update);
3062 CYG_PRECONDITION_THISC();
3063 CYG_PRECONDITION_CLASSC(transaction);
3065 if ((CdlUpdate_ValueChange == update) || (CdlUpdate_ActiveChange == update)) {
3066 this->check_value(transaction);
3067 this->check_requires(transaction);
3070 CYG_REPORT_RETURN();
3073 // ----------------------------------------------------------------------------
3074 // Should this node be active. In addition to the base class' checks that
3075 // the parent is active and enabled, any active_if constraints need
3079 CdlValuableBody::test_active(CdlTransaction transaction)
3081 CYG_REPORT_FUNCNAMETYPE("CdlValuable::test_active", "result %d");
3082 CYG_REPORT_FUNCARG2XV(this, transaction);
3083 CYG_PRECONDITION_THISC();
3084 CYG_PRECONDITION_CLASSC(transaction);
3087 if (!this->CdlNodeBody::test_active(transaction)) {
3092 std::vector<CdlProperty> active_if_properties;
3093 std::vector<CdlProperty>::const_iterator prop_i;
3095 this->get_properties(CdlPropertyId_ActiveIf, active_if_properties);
3096 for (prop_i = active_if_properties.begin(); result && (prop_i != active_if_properties.end()); prop_i++) {
3098 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3099 CYG_ASSERT_CLASSC(gexpr);
3100 CdlEvalContext context(transaction, this, gexpr);
3102 if (!gexpr->eval(context)) {
3105 } catch(CdlEvalException e) {
3106 // Hmmm, an active_if property cannot be evaluated.
3107 // Tricky. If the node is inactive then its conflicts
3108 // are ignored, which would be a bad thing. For now
3109 // assume that the node is active, unless it was already
3110 // inactive for other reasons.
3115 CYG_REPORT_RETVAL(result);
3120 //{{{ CdlValuable modify operations
3122 // ----------------------------------------------------------------------------
3123 // Start with the non-transaction versions. These allocate a new transaction,
3124 // perform their operation in the context of that transaction, and then
3125 // commit the transaction.
3128 CdlValuableBody::set_source(CdlValueSource source)
3130 CYG_REPORT_FUNCNAME("CdlValuable::set_source (no transaction)");
3131 CYG_REPORT_FUNCARG2XV(this, source);
3132 CYG_PRECONDITION_THISC();
3134 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3135 this->set_source(transaction, source);
3136 transaction->body();
3139 CYG_REPORT_RETURN();
3143 CdlValuableBody::invalidate_source(CdlValueSource source)
3145 CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source (no transaction)");
3146 CYG_REPORT_FUNCARG2XV(this, source);
3147 CYG_PRECONDITION_THISC();
3149 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3150 this->invalidate_source(transaction, source);
3151 transaction->body();
3154 CYG_REPORT_RETURN();
3158 CdlValuableBody::set_enabled(bool val, CdlValueSource source)
3160 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled (no transaction)");
3161 CYG_REPORT_FUNCARG3XV(this, val, source);
3162 CYG_PRECONDITION_THISC();
3164 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3165 this->set_enabled(transaction, val, source);
3166 transaction->body();
3169 CYG_REPORT_RETURN();
3173 CdlValuableBody::set_value(CdlSimpleValue& val, CdlValueSource source)
3175 CYG_REPORT_FUNCNAME("CdlValuable::set_value (no transaction)");
3176 CYG_REPORT_FUNCARG3XV(this, &val, source);
3177 CYG_PRECONDITION_THISC();
3179 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3180 this->set_value(transaction, val, source);
3181 transaction->body();
3184 CYG_REPORT_RETURN();
3188 CdlValuableBody::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
3190 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled_and_value (no transaction)");
3191 CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
3192 CYG_PRECONDITION_THISC();
3194 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3195 this->set_enabled_and_value(transaction, enabled_arg, val, source);
3196 transaction->body();
3199 CYG_REPORT_RETURN();
3203 CdlValuableBody::set(CdlSimpleValue& val, CdlValueSource source)
3205 CYG_REPORT_FUNCNAME("CdlValuable::set (no transaction)");
3206 CYG_REPORT_FUNCARG3XV(this, &val, source);
3207 CYG_PRECONDITION_THISC();
3209 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3210 this->set(transaction, val, source);
3211 transaction->body();
3214 CYG_REPORT_RETURN();
3217 // ----------------------------------------------------------------------------
3218 // These member functions operate in the context of a transaction. The
3221 // 1) find out the state before the change
3222 // 2) make a local CdlValue copy, and modify it.
3223 // 3) update the value held in the transaction.
3225 // Values checks etc. happen during propagation, mainly from inside
3226 // the update handler. There is code in CdlTransaction::set_whole_value()
3227 // to avoid unnecessary propagation.
3230 CdlValuableBody::set_source(CdlTransaction transaction, CdlValueSource source)
3232 CYG_REPORT_FUNCNAME("CdlValuable::set_source");
3233 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3234 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3235 CYG_PRECONDITION_THISC();
3236 CYG_PRECONDITION_CLASSC(transaction);
3238 const CdlValue& old_value = transaction->get_whole_value(this);
3239 CdlValue new_value = old_value;
3240 new_value.set_source(source);
3241 transaction->set_whole_value(this, old_value, new_value);
3243 CYG_REPORT_RETURN();
3247 CdlValuableBody::invalidate_source(CdlTransaction transaction, CdlValueSource source)
3249 CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source");
3250 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3251 CYG_PRECONDITION_THISC();
3252 CYG_PRECONDITION_CLASSC(transaction);
3254 const CdlValue& old_value = transaction->get_whole_value(this);
3255 CdlValue new_value = old_value;
3256 new_value.invalidate_source(source);
3257 transaction->set_whole_value(this, old_value, new_value);
3259 CYG_REPORT_RETURN();
3263 CdlValuableBody::set_enabled(CdlTransaction transaction, bool enabled_arg, CdlValueSource source)
3265 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3266 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3267 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3268 CYG_PRECONDITION_THISC();
3269 CYG_PRECONDITION_CLASSC(transaction);
3271 const CdlValue& old_value = transaction->get_whole_value(this);
3272 CdlValue new_value = old_value;
3273 new_value.set_enabled(enabled_arg, source);
3274 transaction->set_whole_value(this, old_value, new_value);
3276 CYG_REPORT_RETURN();
3280 CdlValuableBody::set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3282 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3283 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3284 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3285 CYG_PRECONDITION_THISC();
3286 CYG_PRECONDITION_CLASSC(transaction);
3288 const CdlValue& old_value = transaction->get_whole_value(this);
3289 CdlValue new_value = old_value;
3290 new_value.set_value(val, source);
3291 transaction->set_whole_value(this, old_value, new_value);
3293 CYG_REPORT_RETURN();
3297 CdlValuableBody::set_enabled_and_value(CdlTransaction transaction, bool enabled_arg, CdlSimpleValue& val,
3298 CdlValueSource source)
3300 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3301 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3302 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3303 CYG_PRECONDITION_THISC();
3304 CYG_PRECONDITION_CLASSC(transaction);
3306 const CdlValue& old_value = transaction->get_whole_value(this);
3307 CdlValue new_value = old_value;
3308 new_value.set_enabled_and_value(enabled_arg, val, source);
3309 transaction->set_whole_value(this, old_value, new_value);
3311 CYG_REPORT_RETURN();
3315 CdlValuableBody::set(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3317 CYG_REPORT_FUNCNAME("CdlValuable::set");
3318 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3319 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3320 CYG_PRECONDITION_THISC();
3321 CYG_PRECONDITION_CLASSC(transaction);
3323 const CdlValue& old_value = transaction->get_whole_value(this);
3324 CdlValue new_value = old_value;
3325 new_value.set(val, source);
3326 transaction->set_whole_value(this, old_value, new_value);
3328 CYG_REPORT_RETURN();
3332 CdlValuableBody::set(CdlTransaction transaction, const CdlValue& val)
3334 CYG_REPORT_FUNCNAME("CdlValuable::set");
3335 CYG_REPORT_FUNCARG2XV(this, transaction);
3336 CYG_PRECONDITION_THISC();
3337 CYG_PRECONDITION_CLASSC(transaction);
3339 const CdlValue& old_value = transaction->get_whole_value(this);
3340 CdlValue new_value = val;
3341 transaction->set_whole_value(this, old_value, new_value);
3343 CYG_REPORT_RETURN();
3347 //{{{ CdlValuable basics
3349 // ----------------------------------------------------------------------------
3350 // The CdlValuable class implements the concept of CDL objects that take
3351 // a value. There are lots of properties associated with that.
3353 CdlValuableBody::CdlValuableBody(CdlValueFlavor flavor)
3356 CYG_REPORT_FUNCNAME("CdlValuable:: default constructor");
3357 CYG_REPORT_FUNCARG1XV(this);
3359 cdlvaluablebody_cookie = CdlValuableBody_Magic;
3360 CYGDBG_MEMLEAK_CONSTRUCTOR();
3362 CYG_POSTCONDITION_THISC();
3363 CYG_REPORT_RETURN();
3366 CdlValuableBody::~CdlValuableBody()
3368 CYG_REPORT_FUNCNAME("CdlValuableBody:: destructor");
3369 CYG_REPORT_FUNCARG1XV(this);
3370 CYG_PRECONDITION_THISC();
3372 cdlvaluablebody_cookie = CdlValuableBody_Invalid;
3373 CYGDBG_MEMLEAK_DESTRUCTOR();
3375 CYG_REPORT_RETURN();
3378 // ----------------------------------------------------------------------------
3381 CdlValuableBody::get_class_name() const
3383 CYG_REPORT_FUNCNAME("CdlValuable::get_class_name");
3384 CYG_PRECONDITION_THISC();
3385 CYG_REPORT_RETURN();
3389 // ----------------------------------------------------------------------------
3391 CdlValuableBody::check_this(cyg_assert_class_zeal zeal) const
3393 if (CdlValuableBody_Magic != cdlvaluablebody_cookie) {
3396 CYGDBG_MEMLEAK_CHECKTHIS();
3398 if (has_property(CdlPropertyId_Calculated) && (CdlValueSource_Default != value.get_source())) {
3399 CYG_FAIL("Calculated valuables can only have a default value.");
3403 return CdlNodeBody::check_this(zeal) && value.check_this(zeal);
3407 //{{{ CdlValuable parsing support
3409 // ----------------------------------------------------------------------------
3410 // Parsing support. Adding the appropriate parsers is straightforward.
3413 CdlValuableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
3415 CYG_REPORT_FUNCNAME("CdlValuable::add_property_parsers");
3417 static CdlInterpreterCommandEntry commands[] =
3419 CdlInterpreterCommandEntry("active_if", &parse_active_if ),
3420 CdlInterpreterCommandEntry("calculated", &parse_calculated ),
3421 CdlInterpreterCommandEntry("check_proc", &parse_check_proc ),
3422 CdlInterpreterCommandEntry("default_value", &parse_default_value),
3423 CdlInterpreterCommandEntry("dialog", &parse_dialog ),
3424 CdlInterpreterCommandEntry("entry_proc", &parse_entry_proc ),
3425 CdlInterpreterCommandEntry("flavor", &parse_flavor ),
3426 CdlInterpreterCommandEntry("group", &parse_group ),
3427 CdlInterpreterCommandEntry("implements", &parse_implements ),
3428 CdlInterpreterCommandEntry("legal_values", &parse_legal_values ),
3429 CdlInterpreterCommandEntry("requires", &parse_requires ),
3430 CdlInterpreterCommandEntry("wizard", &parse_wizard ),
3431 CdlInterpreterCommandEntry("", 0 )
3434 for (int i = 0; commands[i].command != 0; i++) {
3435 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
3436 for (j = parsers.begin(); j != parsers.end(); j++) {
3437 if (commands[i].name == j->name) {
3438 if (commands[i].command != j->command) {
3439 CYG_FAIL("Property names are being re-used");
3444 if (j == parsers.end()) {
3445 parsers.push_back(commands[i]);
3448 CdlNodeBody::add_property_parsers(parsers);
3450 CYG_REPORT_RETURN();
3453 // Validatation is quite a bit more complicated...
3455 CdlValuableBody::check_properties(CdlInterpreter interp)
3457 CYG_REPORT_FUNCNAME("CdlValuable::check_properties");
3458 CYG_REPORT_FUNCARG2XV(this, interp);
3459 CYG_PRECONDITION_THISC();
3460 CYG_PRECONDITION_CLASSC(interp);
3462 // There should be at most one of flavor, entry_proc, check_proc,
3463 // default_value, legal_values, dialog, and calculated. There can
3464 // be any number of active_if, requires, and implements.
3465 // NOTE: should multiple entry_proc's and check_proc's be allowed?
3466 // This could prove useful if there are a sensible number
3467 // of library check_proc's.
3468 if (count_properties(CdlPropertyId_Flavor) > 1) {
3469 CdlParse::report_error(interp, "", "There should be at most one flavor property.");
3471 if (count_properties(CdlPropertyId_EntryProc) > 1) {
3472 CdlParse::report_error(interp, "", "There should be at most one entry_proc property.");
3474 if (count_properties(CdlPropertyId_CheckProc) > 1) {
3475 CdlParse::report_error(interp, "", "There should be at most one check_proc property.");
3477 if (count_properties(CdlPropertyId_DefaultValue) > 1) {
3478 CdlParse::report_error(interp, "", "There should be at most one default_value property.");
3480 if (count_properties(CdlPropertyId_LegalValues) > 1) {
3481 CdlParse::report_error(interp, "", "There should be at most one legal_values property.");
3483 if (count_properties(CdlPropertyId_Dialog) > 1) {
3484 CdlParse::report_error(interp, "", "There should be at most one dialog property.");
3486 if (count_properties(CdlPropertyId_Wizard) > 1) {
3487 CdlParse::report_error(interp, "", "There should be at most one wizard property.");
3489 if (count_properties(CdlPropertyId_Calculated) > 1) {
3490 CdlParse::report_error(interp, "", "There should be at most one calculated property.");
3493 // If there is a flavor property, update the flavor in the base class
3494 if (has_property(CdlPropertyId_Flavor)) {
3495 CdlProperty_String flavor_property = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Flavor));
3496 CYG_ASSERTC(0 != flavor_property);
3498 std::string flavor_string = flavor_property->get_string();
3499 CdlValueFlavor flavor;
3500 // The property parsing code should have caught any problems already.
3501 if (!Cdl::string_to_flavor(flavor_string, flavor)) {
3502 CdlParse::report_error(interp, "", "Invalid flavor " + flavor_string);
3504 value.set_flavor(flavor);
3507 // If the flavor is "none" then the entity is not modifiable,
3508 // and most of the properties do not make sense. However this
3509 // is not enforced at parse-time: temporarily switching to
3510 // flavor none may make sense during debugging.
3511 // FIXME: no longer correct
3514 // For boolean entities legal_values does not make much sense.
3515 // In theory a legal_values property could be used to restrict
3516 // the value to just true or just false, but the same effect
3517 // can be achieved more sensibly with a "requires" property.
3519 // check_proc is allowed, this can be used to check programatically
3520 // that the current value is legal.
3521 if (CdlValueFlavor_Bool == get_flavor()) {
3522 if (has_property(CdlPropertyId_LegalValues)) {
3523 CdlParse::report_error(interp, "", "The \"legal_values\" property is not applicable to boolean entities.");
3527 // default_value and calculated are mutually exclusive
3528 if (has_property(CdlPropertyId_Calculated) && has_property(CdlPropertyId_DefaultValue)) {
3529 CdlParse::report_error(interp, "", "The properties \"default_value\" and \"calculated\" cannot be used together.");
3533 // Dialog is not mutually exclusive with entry_proc.
3534 // Custom dialogs may not be supported, in which case it is likely that
3535 // a text entry widget will be used and an entry_proc may well be
3537 if (has_property(CdlPropertyId_Dialog) && has_property(CdlPropertyId_EntryProc)) {
3538 CdlParse::report_error(interp, "", "The properties \"dialog\" and \"entry_proc\" cannot be used together.");
3542 // All of the expressions may be invalid because of unresolved references,
3543 // ditto for implements and for dialog.
3545 CdlNodeBody::check_properties(interp);
3547 CYG_REPORT_RETURN();
3551 //{{{ CdlValuable persistence support
3553 // ----------------------------------------------------------------------------
3555 CdlValuableBody::initialize_savefile_support(CdlToplevel toplevel, std::string major_command)
3557 CYG_REPORT_FUNCNAME("CdlValuable::initialize_savefile_support");
3558 CYG_PRECONDITION_CLASSC(toplevel);
3559 CYG_PRECONDITIONC("" != major_command);
3561 toplevel->add_savefile_subcommand(major_command, "value_source", 0, &savefile_value_source_command);
3562 toplevel->add_savefile_subcommand(major_command, "user_value", 0, &savefile_user_value_command);
3563 toplevel->add_savefile_subcommand(major_command, "wizard_value", 0, &savefile_wizard_value_command);
3564 toplevel->add_savefile_subcommand(major_command, "inferred_value", 0, &savefile_inferred_value_command);
3566 CYG_REPORT_RETURN();
3569 // ----------------------------------------------------------------------------
3570 // Is a savefile entry actually needed for this valuable? When performing
3571 // a minimal save there is no point in outputting valuables which have
3574 CdlValuableBody::value_savefile_entry_needed() const
3576 CYG_REPORT_FUNCNAMETYPE("CdlValuable::value_savefile_entry_needed", "result %d");
3577 CYG_REPORT_FUNCARG1XV(this);
3578 CYG_PRECONDITION_THISC();
3580 bool result = false;
3582 if (this->is_modifiable()) {
3583 if (this->has_source(CdlValueSource_User) ||
3584 this->has_source(CdlValueSource_Wizard) ||
3585 this->has_source(CdlValueSource_Inferred)) {
3591 CYG_REPORT_RETVAL(result);
3595 // ----------------------------------------------------------------------------
3596 // This utility is useful for outputting a particular value source
3598 static std::string one = "1"; // Needed to avoid confusing the compiler
3599 static std::string zero = "0";
3602 value_to_string(CdlValuable valuable, CdlValueSource source)
3604 CYG_REPORT_FUNCNAME("value_to_string");
3606 std::string data = "";
3608 switch(valuable->get_flavor()) {
3609 case CdlValueFlavor_Bool :
3610 data += (valuable->is_enabled(source) ? one : zero);
3612 case CdlValueFlavor_BoolData :
3613 data += (valuable->is_enabled(source) ? one : zero) + " " +
3614 CdlInterpreterBody::quote(valuable->get_value(source));
3616 case CdlValueFlavor_Data:
3617 data += CdlInterpreterBody::quote(valuable->get_value(source));
3620 CYG_FAIL("Invalid value flavor detected");
3626 // Another utility to figure out the expected value source, given which
3627 // sources are available.
3628 static CdlValueSource
3629 get_expected_source(CdlValuable valuable)
3631 CYG_REPORT_FUNCNAMETYPE("get_expected_source", "result %d");
3632 CYG_REPORT_FUNCARG1XV(valuable);
3634 CdlValueSource expected_source = CdlValueSource_Default;
3636 if (valuable->has_source(CdlValueSource_User)) {
3637 expected_source = CdlValueSource_User;
3638 } else if (valuable->has_source(CdlValueSource_Wizard)) {
3639 expected_source = CdlValueSource_Wizard;
3640 } else if (valuable->has_source(CdlValueSource_Inferred)) {
3641 expected_source = CdlValueSource_Inferred;
3644 CYG_REPORT_RETVAL((int) expected_source);
3645 return expected_source;
3648 // And another utility, to list the valuables listed in an expression.
3649 // e.g. for an expression of the form
3651 // requires (AAA + BBB) > CCC
3653 // this would produce:
3659 // No indentation happens here, instead the calling code is assumed
3660 // to use multiline_comment()
3662 follow_expr_references(CdlProperty property, CdlExpression expr)
3664 CYG_REPORT_FUNCNAME("follow_expr_references");
3665 CYG_REPORT_FUNCARG1XV(expr);
3666 CYG_PRECONDITION_CLASSC(expr);
3668 std::string data = "";
3669 CdlSimpleValue simple_value;
3670 std::vector<CdlReference>::const_iterator ref_i;
3672 for (ref_i = expr->references.begin(); ref_i != expr->references.end(); ref_i++) {
3673 const std::string& refname = ref_i->get_destination_name();
3674 CdlNode refnode = ref_i->get_destination();
3675 CdlValuable refvaluable = 0;
3677 refvaluable = dynamic_cast<CdlValuable>(refnode);
3679 data += refname + " ";
3680 if (0 == refvaluable) {
3681 data += "(unknown) == 0";
3683 CdlEvalContext context(0, refvaluable, property);
3684 CdlSimpleValue::eval_valuable(context, refvaluable, simple_value);
3685 data += "== " + CdlInterpreterBody::quote(simple_value.get_value());
3690 CYG_REPORT_RETURN();
3694 // ----------------------------------------------------------------------------
3697 CdlValuableBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool modifiable, bool minimal)
3699 CYG_REPORT_FUNCNAME("CdlValuable::save");
3700 CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
3701 CYG_PRECONDITION_THISC();
3702 CYG_PRECONDITION_CLASSC(interp);
3704 std::string data = "";
3705 std::string indent_string = std::string(indentation, ' ');
3706 std::string tmp_value = "";
3707 CdlSimpleValue simple_value;
3709 // If performing a minimal save, the only fields of interest are the
3710 // user value, the wizard value, the inferred value, and the value source.
3711 // Not all of these need be present.
3713 // Having two places where these fields get output is unfortunate,
3714 // but the alternative is an awful lot of "if (minimal)" tests
3715 // in the main code.
3719 if (this->has_source(CdlValueSource_User)) {
3720 data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3722 if (this->has_source(CdlValueSource_Wizard)) {
3723 data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3725 if (this->has_source(CdlValueSource_Inferred)) {
3726 data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3728 CdlValueSource expected_source = get_expected_source(this);
3729 if (expected_source != this->get_source()) {
3730 std::string current_source_string;
3731 if (!Cdl::source_to_string(this->get_source(), current_source_string)) {
3732 CYG_FAIL("Invalid current value source detected");
3734 data += indent_string + "value_source " + current_source_string + "\n";
3740 // Right at the start, indicate whether or not this property is active.
3741 if (!this->is_active()) {
3742 data += indent_string + "# This option is not active\n";
3743 // If the entity is inactive because the parent is inactive or disabled,
3744 // say so here. This is in addition to any unsatisfied active_if
3745 // conditions, which will be reported below.
3746 CdlContainer parent = this->get_parent();
3747 if (!parent->is_active()) {
3748 data += indent_string + "# The parent " + parent->get_name() + " is not active\n";
3750 CdlValuable tmp = dynamic_cast<CdlValuable>(parent);
3751 if ((0 != tmp) && !tmp->is_enabled()) {
3752 data += indent_string + "# The parent " + parent->get_name() + " is disabled\n";
3755 if (this->has_active_if_conditions()) {
3756 std::vector<CdlProperty_GoalExpression> active_if_conditions;
3757 this->get_active_if_conditions(active_if_conditions);
3758 std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3759 for (expr_i = active_if_conditions.begin(); expr_i != active_if_conditions.end(); expr_i++) {
3760 data += indent_string + "# ActiveIf constraint: " +
3761 CdlInterpreterBody::extend_comment((*expr_i)->get_original_string(), indentation, 4) +
3764 CdlExpression expr = (*expr_i)->get_expression();
3765 data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3766 CdlEvalContext context(0, this, *expr_i);
3767 bool active_if_value = false;
3769 active_if_value = (*expr_i)->eval(context);
3770 } catch(CdlEvalException e) {
3771 active_if_value = false;
3772 } catch(std::bad_alloc) {
3775 data += indent_string + "# --> " + (active_if_value ? one : zero) + "\n";
3779 // If there has been any information related to the active status,
3780 // add a blank line before we start worrying about values.
3781 if (0 < data.size()) {
3785 if (CdlValueFlavor_None == this->get_flavor()) {
3786 data += indent_string + "# There is no associated value.\n";
3787 } else if (this->has_property(CdlPropertyId_Calculated)) {
3788 CdlProperty_Expression expr = this->get_calculated_expression();
3789 data += indent_string + "# Calculated value: " +
3790 CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + '\n';
3791 data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3792 } else if (!modifiable) {
3793 data += indent_string + "# This value cannot be modified here.\n";
3796 // Output the flavor. This clutters up the savefile a bit.
3797 // However it is necessary so that the user can distinguish
3798 // between bool, booldata and data items
3799 switch(this->get_flavor()) {
3800 case CdlValueFlavor_Bool:
3801 data += indent_string + "# Flavor: bool\n";
3803 case CdlValueFlavor_BoolData:
3804 data += indent_string + "# Flavor: booldata\n";
3806 case CdlValueFlavor_Data:
3807 data += indent_string + "# Flavor: data\n";
3813 // If the value is not modifiable, just list the current value.
3814 // This is not in a form that allows users to change it easily.
3816 switch(this->get_flavor()) {
3817 case CdlValueFlavor_None :
3819 case CdlValueFlavor_Bool :
3820 data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + '\n';
3822 case CdlValueFlavor_BoolData :
3823 data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + " " +
3824 CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3826 case CdlValueFlavor_Data :
3827 data += indent_string + "# Current_value: " +
3828 CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3834 } else if (CdlValueFlavor_None != this->get_flavor()) {
3836 // If there is a user value, output it. Otherwise output
3837 // a comment that allows users to edit the user value conveniently.
3838 // It is assumed that the user will want a value similar to the
3839 // default one, so that is provided as the starting point
3840 if (this->has_source(CdlValueSource_User)) {
3841 data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3843 data += indent_string + "# No user value, uncomment the following line to provide one.\n" +
3844 indent_string + "# user_value " +
3845 CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 0) + "\n";
3848 // Output a wizard value iff there is one. There is little point
3849 // in letting users edit a wizard value, they should be running
3850 // the wizard itself.
3851 if (this->has_source(CdlValueSource_Wizard)) {
3852 data += indent_string + "# The wizard value should not be edited directly.\n" +
3853 indent_string + "# Instead the wizard should be run again if necessary.\n";
3854 data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3857 // List the inferred value. This needs to be a command,
3858 if (this->has_source(CdlValueSource_Inferred)) {
3859 data += indent_string + "# The inferred value should not be edited directly.\n";
3860 data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3863 // Output the value source iff it is unusual. If the current
3864 // source is the highest priority one then there is no point
3865 // in outputting a command, but a comment is usual. The value
3866 // source needs to come after wizard and inferred values
3867 std::string current_source_string;
3868 CdlValueSource expected_source = get_expected_source(this);
3869 CdlValueSource current_source = this->get_source();
3870 if (!Cdl::source_to_string(current_source, current_source_string)) {
3871 CYG_FAIL("Invalid current value source detected");
3873 if (this->get_source() == expected_source) {
3874 data += indent_string + "# value_source " + current_source_string + "\n";
3876 data += indent_string + "value_source " + current_source_string + "\n";
3879 // Always output the default value as a comment.
3880 data += indent_string + "# Default value: ";
3882 // If there is no default_value expression or if the expression involves
3883 // only constants, just output the current default value. Otherwise
3884 // output both the expression and the value
3885 CdlProperty prop = this->get_property(CdlPropertyId_DefaultValue);
3886 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
3887 if ((0 == expr) || (0 == expr->references.size())) {
3888 // There is no default_value expression, so just output the current value
3889 data += CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4)
3892 data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + "\n";
3893 data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3894 data += indent_string + "# --> " +
3895 CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4) + "\n";
3899 // If there is a legal_values property, add the details.
3900 if (this->has_property(CdlPropertyId_LegalValues)) {
3901 CdlProperty_ListExpression lexpr = this->get_legal_values();
3902 data += indent_string + "# Legal values: " +
3903 CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4) + '\n';
3905 std::vector<CdlExpression>::const_iterator expr_i;
3906 std::vector<std::pair<CdlExpression,CdlExpression> >::const_iterator ranges_i;
3907 for (expr_i = lexpr->data.begin(); expr_i != lexpr->data.end(); expr_i++) {
3908 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, *expr_i), indentation, 4);
3910 for (ranges_i = lexpr->ranges.begin(); ranges_i != lexpr->ranges.end(); ranges_i++) {
3911 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->first), indentation, 4);
3912 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->second), indentation, 4);
3916 // If there is a check_proc property, mention this.
3917 if (this->has_property(CdlPropertyId_CheckProc)) {
3918 data += indent_string + "# There is a check_proc routine that will check the value.\n";
3921 // Output all requires properties
3922 if (this->has_property(CdlPropertyId_Requires)) {
3923 std::vector<CdlProperty_GoalExpression> requires_goals;
3924 this->get_requires_goals(requires_goals);
3925 std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3926 for (expr_i = requires_goals.begin(); expr_i != requires_goals.end(); expr_i++) {
3927 data += indent_string + "# Requires: " +
3928 CdlInterpreterBody::extend_comment((*expr_i)->get_original_string(), indentation, 4) + "\n";
3930 CdlExpression expr = (*expr_i)->get_expression();
3931 data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3932 CdlEvalContext context(0, this, *expr_i);
3933 bool active_if_value = false;
3935 active_if_value = (*expr_i)->eval(context);
3936 } catch(CdlEvalException e) {
3937 active_if_value = false;
3938 } catch(std::bad_alloc) {
3941 data += indent_string + "# --> " + (active_if_value ? one : zero) + "\n";
3945 // Output all dependencies that other entities may have on this one.
3946 const std::vector<CdlReferrer>& referrers = this->get_referrers();
3947 if (0 != referrers.size()) {
3948 data += '\n' + indent_string + "# The following properties are affected by this value\n";
3949 std::vector<CdlReferrer>::const_iterator ref_i;
3950 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
3952 CdlNode source = ref_i->get_source();
3953 CdlProperty source_prop = ref_i->get_source_property();
3954 std::string prop_id = source_prop->get_property_name();
3956 if ((prop_id == CdlPropertyId_ActiveIf) ||
3957 (prop_id == CdlPropertyId_Calculated) ||
3958 (prop_id == CdlPropertyId_DefaultValue) ||
3959 (prop_id == CdlPropertyId_LegalValues) ||
3960 (prop_id == CdlPropertyId_Requires)) {
3962 data += indent_string + "# " + source->get_class_name() + " " + source->get_name() + "\n";
3963 data += indent_string + "# " + prop_id + ": ";
3964 if ((prop_id == CdlPropertyId_Calculated) || (prop_id == CdlPropertyId_DefaultValue)) {
3965 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(source_prop);
3966 CYG_ASSERT_CLASSC(expr);
3967 data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4);
3968 } else if (prop_id == CdlPropertyId_LegalValues) {
3969 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(source_prop);
3970 CYG_ASSERT_CLASSC(lexpr);
3971 data += CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4);
3972 } else if ((prop_id == CdlPropertyId_ActiveIf) || (prop_id == CdlPropertyId_Requires)) {
3973 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(source_prop);
3974 CYG_ASSERT_CLASSC(gexpr);
3975 data += CdlInterpreterBody::extend_comment(gexpr->get_original_string(), indentation, 4);
3983 interp->write_data(chan, data);
3985 CYG_REPORT_RETURN();
3989 CdlValuableBody::savefile_value_source_command(CdlInterpreter interp, int argc, const char* argv[])
3991 CYG_REPORT_FUNCNAME("CdlValuable::savefile_value_source_command");
3992 CYG_REPORT_FUNCARG2XV(interp, argc);
3993 CYG_PRECONDITION_CLASSC(interp);
3995 CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
3996 CYG_ASSERT_CLASSC(valuable);
3997 CdlTransaction transaction = interp->get_transaction();
3998 CYG_ASSERT_CLASSC(transaction);
4000 CdlValueSource source = CdlValueSource_Invalid;
4001 if ((2 != argc) || !Cdl::string_to_source(argv[1], source) || !valuable->has_source(transaction, source)) {
4002 std::string msg = "Invalid value_source command for ";
4003 msg += valuable->get_class_name() + " " + valuable->get_name() + "\n";
4004 if (CdlValueSource_Invalid == source) {
4005 msg += "Expecting one argument, which should \"user\", \"wizard\", \"inferred\" or \"default\"";
4007 msg += "The specified value source is not valid.";
4009 CdlParse::report_error(interp, "", msg);
4011 valuable->set_source(transaction, source);
4018 CdlValuableBody::savefile_xxx_value_command(CdlInterpreter interp, int argc, const char* argv[], CdlValueSource source)
4020 CYG_REPORT_FUNCNAME("CdlValuable::savefile_xxx_value_command");
4021 CYG_REPORT_FUNCARG3XV(interp, argc, source);
4022 CYG_PRECONDITION_CLASSC(interp);
4024 CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
4025 CYG_ASSERT_CLASSC(valuable);
4026 CdlTransaction transact = interp->get_transaction();
4027 CYG_ASSERT_CLASSC(transact);
4031 std::string msg = "";
4032 if (CdlValueFlavor_None == valuable->get_flavor()) {
4033 msg = "Options with flavor \"none\" cannot be modified.";
4035 } else if (!valuable->is_modifiable()) {
4036 msg = "This option is not user-modifiable.";
4039 switch(valuable->get_flavor()) {
4040 case CdlValueFlavor_Bool :
4042 msg = "Invalid boolean value, expecting 0 or 1";
4046 Cdl::string_to_bool(argv[1], x);
4047 valuable->set_enabled(transact, x, source);
4050 case CdlValueFlavor_Data :
4052 msg = "Invalid data value, expecting a single string";
4055 valuable->set_value(transact, argv[1], source);
4058 case CdlValueFlavor_BoolData:
4060 msg = "Invalid booldata value, expecting a boolean followed by a string";
4064 Cdl::string_to_bool(argv[1], x);
4065 valuable->set_enabled_and_value(transact, x, argv[2], source);
4069 CYG_FAIL("Invalid value flavor detected");
4074 if (error || warn) {
4075 msg = std::string("Invalid value command for ") + valuable->get_class_name() + " " + valuable->get_name() + "\n"
4078 CdlParse::report_error(interp, "", msg);
4080 CdlParse::report_warning(interp, "", msg);
4088 CdlValuableBody::savefile_user_value_command(CdlInterpreter interp, int argc, const char* argv[])
4090 CYG_REPORT_FUNCNAME("CdlValuable::savefile_user_value_command");
4091 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_User);
4092 CYG_REPORT_RETURN();
4097 CdlValuableBody::savefile_wizard_value_command(CdlInterpreter interp, int argc, const char* argv[])
4099 CYG_REPORT_FUNCNAME("CdlValuable::savefile_wizard_value_command");
4100 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Wizard);
4101 CYG_REPORT_RETURN();
4106 CdlValuableBody::savefile_inferred_value_command(CdlInterpreter interp, int argc, const char* argv[])
4108 CYG_REPORT_FUNCNAME("CdlValuable::savefile_inferred_value_command");
4109 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Inferred);
4110 CYG_REPORT_RETURN();