]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/value.cxx
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / tools / src / libcdl / value.cxx
1 //{{{  Banner                           
2
3 //============================================================================
4 //
5 //      value.cxx
6 //
7 //      Implementation of value-related CDL classes.
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //                                                                          
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2002 Bart Veer
14 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
15 //
16 // This file is part of the eCos host tools.
17 //
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) 
21 // any later version.
22 // 
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 
26 // more details.
27 // 
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.
31 //
32 // ----------------------------------------------------------------------------
33 //                                                                          
34 //####COPYRIGHTEND####
35 //============================================================================
36 //#####DESCRIPTIONBEGIN####
37 //
38 // Author(s):   bartv
39 // Contact(s):  bartv
40 // Date:        1999/07/12
41 // Version:     0.02
42 //
43 //####DESCRIPTIONEND####
44 //============================================================================
45
46 //}}}
47 //{{{  #include's                       
48
49 // ----------------------------------------------------------------------------
50 #include "cdlconfig.h"
51
52 // Get the infrastructure types, assertions, tracing and similar
53 // facilities.
54 #include <cyg/infra/cyg_ass.h>
55 #include <cyg/infra/cyg_trac.h>
56
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>
61
62 //}}}
63
64 //{{{  Statics                          
65
66 // ----------------------------------------------------------------------------
67 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValue);
68 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListValue);
69 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValuableBody);
70
71 //}}}
72 //{{{  CdlSimpleValue class             
73
74 //{{{  Constructors                     
75
76 // ----------------------------------------------------------------------------
77
78 CdlSimpleValue::CdlSimpleValue()
79 {
80     CYG_REPORT_FUNCNAME("CdlSimpleValue:: default constructor");
81     CYG_REPORT_FUNCARG1XV(this);
82
83     value               = "0";
84     int_value           = 0;
85     double_value        = 0.0;
86     valid_flags         = int_valid | double_valid | string_valid;
87     format              = CdlValueFormat_Default;
88
89     CYG_REPORT_RETURN();
90 }
91
92 CdlSimpleValue::CdlSimpleValue(std::string val)
93 {
94     CYG_REPORT_FUNCNAME("CdlSimpleValue:: string constructor");
95     CYG_REPORT_FUNCARG1XV(this);
96
97     value               = val;
98     int_value           = 0;
99     double_value        = 0.0;
100     valid_flags         = string_valid;
101     format              = CdlValueFormat_Default;
102     
103     CYG_REPORT_RETURN();
104 }
105
106 CdlSimpleValue::CdlSimpleValue(cdl_int val)
107 {
108     CYG_REPORT_FUNCNAME("CdlSimpleValue:: int constructor");
109     CYG_REPORT_FUNCARG1XV(this);
110
111     value               = "0";
112     int_value           = val;
113     double_value        = 0.0;
114     valid_flags         = int_valid;
115     format              = CdlValueFormat_Default;
116     
117     CYG_REPORT_RETURN();
118 }
119
120 CdlSimpleValue::CdlSimpleValue(double val)
121 {
122     CYG_REPORT_FUNCNAME("CdlSimpleValue:: double constructor");
123     CYG_REPORT_FUNCARG1XV(this);
124
125     value               = "0";
126     int_value           = 0;
127     double_value        = val;
128     valid_flags         = double_valid;
129     format              = CdlValueFormat_Default;
130
131     CYG_REPORT_RETURN();
132 }
133
134 CdlSimpleValue::CdlSimpleValue(bool val)
135 {
136     CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool constructor");
137     CYG_REPORT_FUNCARG2XV(this, val);
138
139     value               = (val) ? "1" : "0";
140     int_value           = (val) ? 1 : 0;
141     double_value        = 0.0;
142     valid_flags         = string_valid | int_valid;
143     format              = CdlValueFormat_Default;
144     
145     CYG_REPORT_RETURN();
146 }
147
148 CdlSimpleValue::CdlSimpleValue(const CdlSimpleValue& original)
149 {
150     CYG_REPORT_FUNCNAME("CdlSimpleValue:: copy constructor");
151     CYG_REPORT_FUNCARG2XV(this, &original);
152
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;
158     
159     CYG_REPORT_RETURN();
160 }
161
162 //}}}
163 //{{{  Destructor                       
164
165 // ----------------------------------------------------------------------------
166
167 CdlSimpleValue::~CdlSimpleValue()
168 {
169     CYG_REPORT_FUNCNAME("CdlsimpleValue:: destructor");
170     CYG_REPORT_FUNCARG1XV(this);
171
172     value               = "";
173     int_value           = 0;
174     double_value        = 0.0;
175     valid_flags         = 0;
176     format              = CdlValueFormat_Default;
177
178     CYG_REPORT_RETURN();
179 }
180
181 //}}}
182 //{{{  Assignment operators             
183
184 // ----------------------------------------------------------------------------
185
186 CdlSimpleValue&
187 CdlSimpleValue::operator=(const CdlSimpleValue& original)
188 {
189     CYG_REPORT_FUNCNAME("CdlSimpleValue:: assignment operator");
190     CYG_REPORT_FUNCARG2XV(this, &original);
191
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;
198     }
199     
200     CYG_REPORT_RETURN();
201     return *this;
202 }
203
204 CdlSimpleValue&
205 CdlSimpleValue::operator=(std::string val)
206 {
207     CYG_REPORT_FUNCNAME("CdlSimpleValue:: string assignment");
208     CYG_REPORT_FUNCARG1XV(this);
209
210     value               = val;
211     int_value           = 0;
212     double_value        = 0.0;
213     valid_flags         = string_valid;
214     format              = CdlValueFormat_Default;
215
216     CYG_REPORT_RETURN();
217     return *this;
218 }
219
220 CdlSimpleValue&
221 CdlSimpleValue::operator=(cdl_int val)
222 {
223     CYG_REPORT_FUNCNAME("CdlSimpleValue:: integer assignment");
224     CYG_REPORT_FUNCARG1XV(this);
225
226     value               = "";
227     int_value           = val;
228     double_value        = 0.0;
229     valid_flags         = int_valid;
230     format              = CdlValueFormat_Default;
231     
232     CYG_REPORT_RETURN();
233     return *this;
234 }
235
236 CdlSimpleValue&
237 CdlSimpleValue::operator=(double val)
238 {
239     CYG_REPORT_FUNCNAME("CdlSimpleValue:: double assignment");
240     CYG_REPORT_FUNCARG1XV(this);
241
242     value               = "";
243     int_value           = 0;
244     double_value        = val;
245     valid_flags         = double_valid;
246     format              = CdlValueFormat_Default;
247
248     CYG_REPORT_RETURN();
249     return *this;
250 }
251
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.
256
257 CdlSimpleValue&
258 CdlSimpleValue::operator=(bool val)
259 {
260     CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool assignment");
261     CYG_REPORT_FUNCARG1XV(this);
262
263     value               = (val) ? "1" : "0";
264     int_value           = (val) ? 1 : 0;
265     double_value        = 0.0;
266     valid_flags         = string_valid | int_valid;
267     format              = CdlValueFormat_Default;
268
269     CYG_REPORT_RETURN();
270     return *this;
271 }
272
273 //}}}
274 //{{{  CdlValuable -> CdlSimpleValue    
275
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.
279
280 void
281 CdlSimpleValue::eval_valuable(CdlEvalContext& context, CdlValuable valuable, CdlSimpleValue& result)
282 {
283     CYG_REPORT_FUNCNAME("CdlSimpleValue:: valuable assignment");
284     CYG_REPORT_FUNCARG3XV(&context, valuable, &result);
285     CYG_PRECONDITION_CLASSC(valuable);
286
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())) {
292         
293         result.value           = "0";
294         result.int_value       = 0;
295         result.double_value    = 0.0;
296         result.valid_flags     = string_valid | int_valid;
297         result.format          = CdlValueFormat_Default;
298         CYG_REPORT_RETURN();
299         return;
300     }
301
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();
305         
306     // Otherwise the value depends on the flavor.
307     switch(val.get_flavor()) {
308       case CdlValueFlavor_None :
309       {
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.
312         result.value           = "1";
313         result.int_value       = 1;
314         result.double_value    = 0.0;
315         result.valid_flags     = string_valid | int_valid;
316         result.format          = CdlValueFormat_Default;
317         break;
318       }
319       case CdlValueFlavor_Bool :
320       {
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;
327         break;
328       }
329       case CdlValueFlavor_BoolData :
330       {
331         if (!val.is_enabled()) {
332                     
333             result.value        = "0";
334             result.int_value    = 0;
335             result.double_value = 0.0;
336             result.valid_flags  = string_valid | int_valid;
337             result.format       = CdlValueFormat_Default;
338                     
339         } else {
340
341             // Just use a copy constructor, let the compiler optimise things.
342             result = val.get_simple_value();
343         }
344         break;
345       }
346       case CdlValueFlavor_Data :
347       {
348         // Just like BoolData, but with no need to check the enabled flag.
349         result = val.get_simple_value();
350         break;
351       }
352       default:
353       {
354         CYG_FAIL("Valuable object with an unknown flavor encountered.");
355       }
356     }
357
358     CYG_REPORT_RETURN();
359 }
360
361 //}}}
362 //{{{  Getting the value                
363
364 // ----------------------------------------------------------------------------
365 // Some of these calls involve conversion operators.
366
367 std::string
368 CdlSimpleValue::get_value() const
369 {
370     CYG_REPORT_FUNCNAME("CdlSimpleValue::get_value");
371     CYG_REPORT_FUNCARG1XV(this);
372
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);
378         } else {
379             CYG_FAIL("Attempt to use uninitialized SimpleValue");
380         }
381         valid_flags |= string_valid;
382     }
383
384     CYG_REPORT_RETURN();
385     return value;
386 }
387
388 bool
389 CdlSimpleValue::has_integer_value() const
390 {
391     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_integer_value", "result %d");
392     CYG_REPORT_FUNCARG1XV(this);
393
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;
398             } else {
399                 valid_flags |= int_invalid;
400             }
401         } else if (valid_flags & string_valid) {
402             if (Cdl::string_to_integer(value, int_value)) {
403                 valid_flags |= int_valid;
404             } else {
405                 valid_flags |= int_invalid;
406             }
407         } else {
408             CYG_FAIL("Attempt to use uninitialized SimpleValue");
409         }
410     }
411     
412     bool result = (valid_flags & int_valid);
413     CYG_REPORT_RETVAL(result);
414     return result;
415 }
416
417 cdl_int
418 CdlSimpleValue::get_integer_value() const
419 {
420     CYG_REPORT_FUNCNAMETYPE("CdlsimpleValue::get_integer_value", "result %ld");
421     CYG_REPORT_FUNCARG1XV(this);
422
423     cdl_int result = 0;
424     if ((valid_flags & int_valid) || has_integer_value()) {
425         result = int_value;
426     }
427
428     CYG_REPORT_RETVAL((int) result);
429     return result;
430 }
431
432 bool
433 CdlSimpleValue::has_double_value() const
434 {
435     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_double_value", "result %d");
436     CYG_REPORT_FUNCARG1XV(this);
437
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;
445             } else {
446                 valid_flags |= double_invalid;
447             }
448         } else {
449             CYG_FAIL("Attempt to use uninitialized SimpleValue");
450         }
451     }
452     bool result = (valid_flags & double_valid);
453     CYG_REPORT_RETVAL(result);
454     return result;
455 }
456
457 double
458 CdlSimpleValue::get_double_value() const
459 {
460     CYG_REPORT_FUNCNAME("CdlSimpleValue::get_double_value");
461     CYG_REPORT_FUNCARG1XV(this);
462
463     double result = 0.0;
464     if ((valid_flags & double_valid) || has_double_value()) {
465         result = double_value;
466     }
467
468     CYG_REPORT_RETURN();
469     return result;
470 }
471
472 bool
473 CdlSimpleValue::get_bool_value() const
474 {
475     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_bool_value", "result %d");
476     CYG_REPORT_FUNCARG1XV(this);
477
478     bool result = false;
479     if (valid_flags & int_valid) {
480         if (0 != int_value) {
481             result = true;
482         }
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)) {
491             if ("" == value) {
492                 result = false;
493             } else {
494                 result = true;
495             }
496         }
497     } else {
498         // No value defined, default to false.
499         result = false;
500     }
501
502     CYG_REPORT_RETVAL(result);
503     return result;
504 }
505
506 //}}}
507 //{{{  Updating the value               
508
509 // ----------------------------------------------------------------------------
510 // Normally the assignment operators will be used for this instead.
511
512 void
513 CdlSimpleValue::set_value(std::string val, CdlValueFormat new_format)
514 {
515     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value (string)");
516     CYG_REPORT_FUNCARG1XV(this);
517
518     value               = val;
519     int_value           = 0;
520     double_value        = 0.0;
521     valid_flags         = string_valid;
522     format              = new_format;
523 }
524
525
526 void
527 CdlSimpleValue::set_integer_value(cdl_int val, CdlValueFormat new_format)
528 {
529     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_integer_value");
530     CYG_REPORT_FUNCARG2XV(this, (int) val);
531
532     value               = "";
533     int_value           = val;
534     double_value        = 0.0;
535     valid_flags         = int_valid;
536     format              = new_format;
537
538     CYG_REPORT_RETURN();
539 }
540
541
542 void
543 CdlSimpleValue::set_double_value(double val, CdlValueFormat new_format)
544 {
545     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_double_value");
546     CYG_REPORT_FUNCARG1XV(this);
547
548     value               = "";
549     int_value           = 0;
550     double_value        = val;
551     valid_flags         = double_valid;
552     format              = new_format;
553
554     CYG_REPORT_RETURN();
555 }
556
557 //}}}
558 //{{{  Value format support             
559
560 // ----------------------------------------------------------------------------
561
562 CdlValueFormat
563 CdlSimpleValue::get_value_format() const
564 {
565     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_value_format", "result %d");
566     CYG_REPORT_FUNCARG1XV(this);
567
568     CdlValueFormat result = format;
569     CYG_REPORT_RETVAL(result);
570     return result;
571 }
572
573 void
574 CdlSimpleValue::set_value_format(CdlValueFormat new_format)
575 {
576     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
577     CYG_REPORT_FUNCARG2XV(this, new_format);
578
579     format      = new_format;
580     
581     CYG_REPORT_RETURN();
582 }
583
584 void
585 CdlSimpleValue::set_value_format(CdlSimpleValue& other_val)
586 {
587     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format (simple val)");
588     CYG_REPORT_FUNCARG2XV(this, &other_val);
589
590     format = other_val.format;
591
592     CYG_REPORT_RETURN();
593 }
594
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.
598 //
599 // e.g. 0x1000 + 4 -> 0x1004
600 //      10 + 0x100 -> 0x10A
601 //      10 + 32    -> 42
602
603 void
604 CdlSimpleValue::set_value_format(CdlSimpleValue& val1, CdlSimpleValue& val2)
605 {
606     CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
607     CYG_REPORT_FUNCARG3XV(this, &val1, &val2);
608
609     format = (CdlValueFormat_Default != val1.format) ? val1.format : val2.format;
610
611     CYG_REPORT_RETURN();
612 }
613
614 //}}}
615 //{{{  Comparison operators             
616
617 // ----------------------------------------------------------------------------
618
619 bool
620 CdlSimpleValue::operator==(const CdlSimpleValue& other) const
621 {
622     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator==", "result %d");
623     CYG_REPORT_FUNCARG2XV(this, &other);
624
625     bool result = false;
626     
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);
632         }
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);
638         }
639     } else {
640         std::string val1 = get_value();
641         std::string val2 = other.get_value();
642         result = (val1 == val2);
643     }
644     
645     CYG_REPORT_RETVAL(result);
646     return result;
647 }
648
649 bool
650 CdlSimpleValue::operator!=(const CdlSimpleValue& other) const
651 {
652     CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator!=", "result %d");
653     CYG_REPORT_FUNCARG2XV(this, &other);
654
655     bool result = true;
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);
661         }
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);
667         }
668     } else {
669         std::string val1 = get_value();
670         std::string val2 = other.get_value();
671         result = (val1 != val2);
672     }
673
674
675     CYG_REPORT_RETVAL(result);
676     return result;
677 }
678
679 //}}}
680
681 //}}}
682 //{{{  CdlValue class                   
683
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.
688
689 static const int CdlValue_number_of_sources = 4;
690
691 //{{{  Constructors                             
692
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().
697
698 CdlValue::CdlValue(CdlValueFlavor flavor_arg)
699 {
700     CYG_REPORT_FUNCNAME("CdlValue:: constructor");
701     CYG_REPORT_FUNCARG1XV(this);
702
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;
712
713     // The SimpleValues will initialize themselves.
714     
715     cdlvalue_cookie         = CdlValue_Magic;
716     CYGDBG_MEMLEAK_CONSTRUCTOR();
717
718     // This cannot happen until after the object is valid.
719     set_flavor(flavor_arg);
720         
721     CYG_POSTCONDITION_THISC();
722     CYG_REPORT_RETURN();
723 }
724
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.
729
730 CdlValue::CdlValue(const CdlValue& original)
731 {
732     CYG_REPORT_FUNCNAME("CdlValue:: copy constructor");
733     CYG_REPORT_FUNCARG2XV(this, &original);
734     CYG_INVARIANT_CLASSOC(CdlValue, original);
735
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];
742     }
743
744     cdlvalue_cookie = CdlValue_Magic;
745     CYGDBG_MEMLEAK_CONSTRUCTOR();
746     
747     CYG_POSTCONDITION_THISC();
748     CYG_REPORT_RETURN();
749 }
750
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.
754
755 CdlValue& CdlValue::operator=(const CdlValue& original)
756 {
757     CYG_REPORT_FUNCNAME("CdlValue:: assignment operator");
758     CYG_REPORT_FUNCARG2XV(this, &original);
759     CYG_INVARIANT_CLASSOC(CdlValue, original);
760
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];
768         }
769     }
770
771     cdlvalue_cookie = CdlValue_Magic;
772     CYG_POSTCONDITION_THISC();
773     CYG_REPORT_RETURN();
774     return *this;
775 }
776
777 //}}}
778 //{{{  Destructor                               
779
780 // ----------------------------------------------------------------------------
781
782 CdlValue::~CdlValue()
783 {
784     CYG_REPORT_FUNCNAME("CdlValue:: destructor");
785     CYG_REPORT_FUNCARG1XV(this);
786     CYG_PRECONDITION_THISC();
787
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;
793         enabled[i]              = false;
794         // The CdlSimpleValue array will take care of itself.
795     }
796     CYGDBG_MEMLEAK_DESTRUCTOR();
797
798     CYG_REPORT_RETURN();
799 }
800
801 //}}}
802 //{{{  check_this()                             
803
804 // ----------------------------------------------------------------------------
805 bool
806 CdlValue::check_this(cyg_assert_class_zeal zeal) const
807 {
808     if (CdlValue_Magic != cdlvalue_cookie) {
809         return false;
810     }
811     CYGDBG_MEMLEAK_CHECKTHIS();
812
813     if (!source_valid[CdlValueSource_Default]) {
814         return false;
815     }
816
817     if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Data == flavor)) {
818         for (int i = 0; i < CdlValue_number_of_sources; i++) {
819             if (!enabled[i]) {
820                 return false;
821             }
822         }
823     }
824     for (int i = 0; i < CdlValue_number_of_sources; i++) {
825         if (source_valid[i]) {
826             if (!values[i].check_this(zeal)) {
827                 return false;
828             }
829         }
830     }
831     
832     return true;
833 }
834
835 //}}}
836 //{{{  Flavor manipulation                      
837
838 // ----------------------------------------------------------------------------
839 // Get hold of the current flavor.
840 CdlValueFlavor
841 CdlValue::get_flavor(void) const
842 {
843     CYG_REPORT_FUNCNAMETYPE("CdlValue::get_flavor", "result %d");
844     CYG_REPORT_FUNCARG1XV(this);
845     CYG_PRECONDITION_THISC();
846
847     CdlValueFlavor result = flavor;
848     CYG_REPORT_RETVAL(result);
849     return result;
850 }
851
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
859 // set_flavor().
860
861 void
862 CdlValue::set_flavor(CdlValueFlavor flavor_arg)
863 {
864     CYG_REPORT_FUNCNAME("CdlValue:: set_flavor");
865     CYG_REPORT_FUNCARG2XV(this, flavor_arg);
866     
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));
872
873     flavor = flavor_arg;
874     switch(flavor) {
875       case CdlValueFlavor_None :
876         {
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;
884             
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;
890             break;
891         }
892           
893       case CdlValueFlavor_Bool :
894         {
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;
905
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.
911 #if 0            
912             CdlSimpleValue simple_val(cdl_int(1));
913 #else
914             CdlSimpleValue simple_val(cdl_int(0));
915 #endif            
916             values[CdlValueSource_Default]      = simple_val;
917             values[CdlValueSource_Inferred]     = simple_val;
918             values[CdlValueSource_Wizard]       = simple_val;
919             values[CdlValueSource_User]         = simple_val;
920             break;
921         }
922           
923       case CdlValueFlavor_BoolData :
924         {
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;
931             break;
932         }
933           
934       case CdlValueFlavor_Data :
935         {
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;
942             break;
943         }
944
945       default :
946         break;
947     }
948     
949     CYG_REPORT_RETURN();
950 }
951
952 //}}}
953 //{{{  Source manipulation                      
954
955 // ----------------------------------------------------------------------------
956
957 void
958 CdlValue::set_source(CdlValueSource source)
959 {
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]);
965
966     current_source = source;
967
968     CYG_REPORT_RETURN();
969 }
970
971 CdlValueSource
972 CdlValue::get_source(void) const
973 {
974     CYG_REPORT_FUNCNAMETYPE("CdlValue::get_source", "source %d");
975     CYG_REPORT_FUNCARG1XV(this);
976     CYG_PRECONDITION_THISC();
977
978     CdlValueSource result = current_source;
979     CYG_REPORT_RETVAL(result);
980     return result;
981 }
982
983 bool
984 CdlValue::has_source(CdlValueSource source) const
985 {
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));
990
991     bool result = source_valid[source];
992     CYG_REPORT_RETVAL(result);
993     return result;
994 }
995
996 // ----------------------------------------------------------------------------
997 // Invalidate a specific source. If that source happens to be the current one,
998 // switch to the highest-priority valid source.
999
1000 void
1001 CdlValue::invalidate_source(CdlValueSource source)
1002 {
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));
1008
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;
1018             } else {
1019                 current_source = CdlValueSource_Default;
1020             }
1021         }
1022     }
1023     
1024     CYG_POSTCONDITIONC(source_valid[current_source]);
1025 }
1026
1027 //}}}
1028 //{{{  Retrieving the data                      
1029
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.
1034 //
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.
1038
1039 bool
1040 CdlValue::is_enabled(CdlValueSource source) const
1041 {
1042     CYG_REPORT_FUNCNAMETYPE("CdlValue::is_enabled", "enabled %d");
1043     CYG_REPORT_FUNCARG2XV(this, source);
1044     CYG_PRECONDITION_THISC();
1045
1046     if (CdlValueSource_Current == source) {
1047         source = current_source;
1048     }
1049     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1050     CYG_PRECONDITIONC(source_valid[source]);
1051
1052     bool result = enabled[source];
1053     CYG_REPORT_RETVAL(result);
1054     return result;
1055 }
1056
1057 // ----------------------------------------------------------------------------
1058 // Access to the value field.
1059
1060 std::string
1061 CdlValue::get_value(CdlValueSource source) const
1062 {
1063     CYG_REPORT_FUNCNAME("CdlValue::get_value");
1064     CYG_REPORT_FUNCARG2XV(this, source);
1065     CYG_PRECONDITION_THISC();
1066
1067     if (CdlValueSource_Current == source) {
1068         source = current_source;
1069     }
1070     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1071     CYG_PRECONDITIONC(source_valid[source]);
1072
1073     std::string result = values[source].get_value();
1074     CYG_REPORT_RETURN();
1075     return result;
1076 }
1077
1078 bool
1079 CdlValue::has_integer_value(CdlValueSource source) const
1080 {
1081     CYG_REPORT_FUNCNAMETYPE("CdlValue::has_integer_value", "result %d");
1082     CYG_REPORT_FUNCARG2XV(this, source);
1083     CYG_INVARIANT_THISC(CdlValue);
1084
1085     if (CdlValueSource_Current == source) {
1086         source = current_source;
1087     }
1088     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1089     CYG_PRECONDITIONC(source_valid[source]);
1090
1091     bool result = values[source].has_integer_value();
1092     CYG_REPORT_RETVAL(result);
1093     return result;
1094 }
1095
1096 bool
1097 CdlValue::has_double_value(CdlValueSource source) const
1098 {
1099     CYG_REPORT_FUNCNAMETYPE("CdlValue::has_value", "result %d");
1100     CYG_REPORT_FUNCARG2XV(this, source);
1101     CYG_INVARIANT_THISC(CdlValue);
1102     
1103     if (CdlValueSource_Current == source) {
1104         source = current_source;
1105     }
1106     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1107     CYG_PRECONDITIONC(source_valid[source]);
1108
1109     bool result = values[source].has_double_value();
1110     CYG_REPORT_RETVAL(result);
1111     return result;
1112 }
1113
1114 cdl_int
1115 CdlValue::get_integer_value(CdlValueSource source) const
1116 {
1117     CYG_REPORT_FUNCNAMETYPE("CdlValue::get_integer_value", "value %ld");
1118     CYG_REPORT_FUNCARG2XV(this, source);
1119     CYG_PRECONDITION_THISC();
1120
1121     if (CdlValueSource_Current == source) {
1122         source = current_source;
1123     }
1124     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1125     CYG_PRECONDITIONC(source_valid[source]);
1126
1127     cdl_int result = values[source].get_integer_value();
1128     CYG_REPORT_RETVAL(result);
1129     return result;
1130 }
1131
1132 double
1133 CdlValue::get_double_value(CdlValueSource source) const
1134 {
1135     CYG_REPORT_FUNCNAME("CdlValue::get_double_value");
1136     CYG_REPORT_FUNCARG2XV(this, source);
1137     CYG_PRECONDITION_THISC();
1138
1139     if (CdlValueSource_Current == source) {
1140         source = current_source;
1141     }
1142     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1143     CYG_PRECONDITIONC(source_valid[source]);
1144
1145     double result = values[source].get_double_value();
1146     CYG_REPORT_RETURN();
1147     return result;
1148 }
1149
1150 CdlSimpleValue
1151 CdlValue::get_simple_value(CdlValueSource source) const
1152 {
1153     CYG_REPORT_FUNCNAME("CdlValue::get_simple_value");
1154     CYG_REPORT_FUNCARG2XV(this, source);
1155     CYG_PRECONDITION_THISC();
1156
1157     if (CdlValueSource_Current == source) {
1158         source = current_source;
1159     }
1160     CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1161     CYG_PRECONDITIONC(source_valid[source]);
1162
1163     CYG_REPORT_RETURN();
1164     return values[source];
1165 }
1166
1167 //}}}
1168 //{{{  Value modification                       
1169
1170 // ----------------------------------------------------------------------------
1171
1172 void
1173 CdlValue::set_enabled(bool val, CdlValueSource source)
1174 {
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));
1180
1181     enabled[source] = val;
1182     source_valid[source] = true;
1183     if (source > current_source) {
1184         current_source = source;
1185     }
1186     
1187     CYG_REPORT_RETURN();
1188 }
1189
1190 void
1191 CdlValue::set_value(CdlSimpleValue& val, CdlValueSource source)
1192 {
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));
1198     
1199     values[source] = val;
1200     source_valid[source] = true;
1201     if (source > current_source) {
1202         current_source = source;
1203     }
1204     
1205     CYG_REPORT_RETURN();
1206 }
1207
1208 void
1209 CdlValue::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
1210 {
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));
1216
1217     enabled[source]      = enabled_arg;
1218     values[source]       = val;
1219     source_valid[source] = true;
1220     if (source > current_source) {
1221         current_source = source;
1222     }
1223     
1224     CYG_REPORT_RETURN();
1225 }
1226
1227 // ----------------------------------------------------------------------------
1228 // Given a SimpleValue, this member function does the right thing
1229 // for the flavor.
1230
1231 void
1232 CdlValue::set(CdlSimpleValue& val, CdlValueSource source)
1233 {
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));
1239
1240     switch(flavor) {
1241       case CdlValueFlavor_Bool:
1242         enabled[source] = val.get_bool_value();
1243         break;
1244
1245       case CdlValueFlavor_BoolData:
1246         if (!val.get_bool_value()) {
1247             enabled[source] = false;
1248             values[source]  = (cdl_int) 0;
1249         } else {
1250             enabled[source] = true;
1251             values[source]  = val;
1252         }
1253         break;
1254                     
1255       case CdlValueFlavor_Data:
1256         values[source] = val;
1257         break;
1258                     
1259       default:
1260         CYG_FAIL("Unknown value flavor detected.");
1261     }
1262     
1263     source_valid[source] = true;
1264     if (source > current_source) {
1265         current_source = source;
1266     }
1267
1268     CYG_REPORT_RETURN();
1269 }
1270
1271 //}}}
1272
1273 //}}}
1274 //{{{  CdlListValue class               
1275
1276 // ----------------------------------------------------------------------------
1277 // List values. Most of this is straightforward.
1278
1279 CdlListValue::CdlListValue()
1280 {
1281     CYG_REPORT_FUNCNAME("CdlListValue:: default constructor");
1282     CYG_REPORT_FUNCARG1XV(this);
1283
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();
1288     
1289     CYG_POSTCONDITION_THISC();
1290     CYG_REPORT_RETURN();
1291 }
1292
1293 CdlListValue::CdlListValue(const CdlListValue& original)
1294 {
1295     CYG_REPORT_FUNCNAME("CdlListValue:: copy constructor");
1296     CYG_REPORT_FUNCARG2XV(this, &original);
1297     CYG_INVARIANT_CLASSOC(CdlListValue, original);
1298     
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();
1305     
1306     CYG_POSTCONDITION_THISC();
1307     CYG_REPORT_RETURN();
1308 }
1309
1310 CdlListValue & CdlListValue::operator=(const CdlListValue& original)
1311 {
1312     CYG_REPORT_FUNCNAME("CdlListValue:: assignment operator");
1313     CYG_REPORT_FUNCARG2XV(this, &original);
1314     CYG_INVARIANT_CLASSOC(CdlListValue, original);
1315
1316     if (this != &original) {
1317         table.clear();
1318         integer_ranges.clear();
1319         double_ranges.clear();
1320         table          = original.table;
1321         integer_ranges = original.integer_ranges;
1322         double_ranges  = original.double_ranges;
1323     }
1324     
1325     CYG_POSTCONDITION_THISC();
1326     CYG_REPORT_RETURN();
1327     return *this;
1328 }
1329
1330 CdlListValue::~CdlListValue()
1331 {
1332     CYG_REPORT_FUNCNAME("CdlListValue:: destructor");
1333     CYG_REPORT_FUNCARG1XV(this);
1334     CYG_PRECONDITION_THISC();
1335
1336     cdllistvalue_cookie = CdlListValue_Invalid;
1337     table.clear();
1338     integer_ranges.clear();
1339     double_ranges.clear();
1340     CYGDBG_MEMLEAK_DESTRUCTOR();
1341     
1342     CYG_REPORT_RETURN();
1343 }
1344
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.
1355
1356 const std::vector<CdlSimpleValue>&
1357 CdlListValue::get_table(void) const
1358 {
1359     CYG_REPORT_FUNCNAME("CdlListValue::get_table");
1360     CYG_REPORT_FUNCARG1XV(this);
1361     CYG_PRECONDITION_THISC();
1362
1363     CYG_REPORT_RETURN();
1364     return table;
1365 }
1366
1367 const std::vector<std::pair<cdl_int, cdl_int> >&
1368 CdlListValue::get_integer_ranges(void) const
1369 {
1370     CYG_REPORT_FUNCNAME("CdlListValue::get_integer_ranges");
1371     CYG_REPORT_FUNCARG1XV(this);
1372     CYG_PRECONDITION_THISC();
1373
1374     CYG_REPORT_RETURN();
1375     return integer_ranges;
1376 }
1377
1378 const std::vector<std::pair<double, double> >&
1379 CdlListValue::get_double_ranges(void) const
1380 {
1381     CYG_REPORT_FUNCNAME("CdlListValue::get_double_ranges");
1382     CYG_REPORT_FUNCARG1XV(this);
1383     CYG_PRECONDITION_THISC();
1384
1385     CYG_REPORT_RETURN();
1386     return double_ranges;
1387 }
1388
1389 // ----------------------------------------------------------------------------
1390 // Membership. This can be quite complicated.
1391 //
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.
1397 //
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.
1402 //
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.
1406 //
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.
1411
1412 bool
1413 CdlListValue::is_member(CdlSimpleValue& val) const
1414 {
1415     CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (CdlSimpleValue)", "result %d");
1416     CYG_REPORT_FUNCARG2XV(this, &val);
1417     CYG_PRECONDITION_THISC();
1418
1419     bool result = false;
1420     if (val.has_integer_value()) {
1421         result = is_member(val.get_integer_value(), false);
1422     }
1423     if (!result && val.has_double_value()) {
1424         result = is_member(val.get_double_value(), false);
1425     }
1426     if (!result) {
1427         result = is_member(val.get_value());
1428     }
1429     
1430     CYG_REPORT_RETVAL(result);
1431     return result;
1432 }
1433
1434 bool
1435 CdlListValue::is_member(std::string val, bool allow_conversions) const
1436 {
1437     CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (string)", "result %d");
1438     CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1439     CYG_PRECONDITION_THISC();
1440
1441     bool        result = false;
1442     if (allow_conversions) {
1443         cdl_int     integer_value;
1444         double      double_value;
1445
1446         if (Cdl::string_to_integer(val, integer_value)) {
1447             result = is_member(integer_value, false);
1448         }
1449         if (!result && Cdl::string_to_double(val, double_value)) {
1450             result = is_member(double_value, false);
1451         }
1452     }
1453     if (!result) {
1454         for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1455             if (val_i->get_value() == val) {
1456                 result = true;
1457                 break;
1458             }
1459         }
1460     }
1461
1462     CYG_REPORT_RETVAL(result);
1463     return result;
1464 }
1465
1466 bool
1467 CdlListValue::is_member(cdl_int val, bool allow_conversions) const
1468 {
1469     CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (int)", "result %d");
1470     CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1471     CYG_PRECONDITION_THISC();
1472
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)) {
1476             result = true;
1477             break;
1478         }
1479     }
1480     if (!result) {
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)) {
1484                 result = true;
1485                 break;
1486             }
1487         }
1488     }
1489     if (!result && allow_conversions) {
1490         double double_value = Cdl::integer_to_double(val);
1491         result = is_member(double_value, false);
1492     }
1493
1494     CYG_REPORT_RETVAL(result);
1495     return result;
1496 }
1497
1498 bool
1499 CdlListValue::is_member(double val, bool allow_conversions) const
1500 {
1501     CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (double)", "result %d");
1502     CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1503     CYG_PRECONDITION_THISC();
1504
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)) {
1508             result = true;
1509             break;
1510         }
1511     }
1512     if (!result) {
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)) {
1516                 result = true;
1517                 break;
1518             }
1519         }
1520     }
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);
1525         }
1526     }
1527
1528     CYG_REPORT_RETVAL(result);
1529     return result;
1530 }
1531
1532 // ----------------------------------------------------------------------------
1533
1534 bool
1535 CdlListValue::check_this(cyg_assert_class_zeal zeal) const
1536 {
1537     if (CdlListValue_Magic != cdllistvalue_cookie) {
1538         return false;
1539     }
1540     CYGDBG_MEMLEAK_CHECKTHIS();
1541
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.
1545     return true;
1546 }
1547
1548 //}}}
1549
1550 //{{{  dialog property                  
1551
1552 // ----------------------------------------------------------------------------
1553 // Syntax: dialog <reference>
1554
1555 void
1556 CdlValuableBody::dialog_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1557                                        CdlUpdate change)
1558 {
1559     CYG_REPORT_FUNCNAME("CdlValuable::dialog_update_handler");
1560     CYG_PRECONDITION_CLASSC(transaction);
1561     CYG_PRECONDITION_CLASSC(source);
1562     CYG_PRECONDITION_CLASSC(prop);
1563     
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)) {
1569
1570         CYG_ASSERT_CLASSC(dest);
1571         CdlDialog dialog = dynamic_cast<CdlDialog>(dest);
1572         if (0 == dialog) {
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);
1576         }
1577         
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);
1581     }
1582
1583     CYG_REPORT_RETURN();
1584 }
1585
1586 int
1587 CdlValuableBody::parse_dialog(CdlInterpreter interp, int argc, const char* argv[])
1588 {
1589     CYG_REPORT_FUNCNAMETYPE("parse_dialog", "result %d");
1590
1591     int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Dialog, 0, 0, false, &dialog_update_handler);
1592     
1593     CYG_REPORT_RETVAL(result);
1594     return result;
1595 }
1596
1597 bool
1598 CdlValuableBody::has_dialog() const
1599 {
1600     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_dialog", "result %d");
1601     CYG_REPORT_FUNCARG1XV(this);
1602     CYG_PRECONDITION_THISC();
1603
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);
1611
1612         CdlNode destination = ref_prop->get_destination();
1613         if (0 != destination) {
1614             CdlDialog dialog = dynamic_cast<CdlDialog>(destination);
1615             if (0 != dialog) {
1616                 result = true;
1617             }
1618         }
1619     }
1620     CYG_REPORT_RETVAL(result);
1621     return result;
1622 }
1623
1624
1625 CdlDialog
1626 CdlValuableBody::get_dialog() const
1627 {
1628     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_dialog", "result %p");
1629     CYG_REPORT_FUNCARG1XV(this);
1630     CYG_PRECONDITION_THISC();
1631
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);
1637
1638         CdlNode destination = ref_prop->get_destination();
1639         if (0 != destination) {
1640             result = dynamic_cast<CdlDialog>(destination);
1641         }
1642     }
1643
1644     CYG_REPORT_RETVAL(result);
1645     return result;
1646 }
1647
1648 //}}}
1649 //{{{  wizard property                  
1650
1651 // ----------------------------------------------------------------------------
1652 // Syntax: wizard <reference>
1653
1654 void
1655 CdlValuableBody::wizard_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1656                                        CdlUpdate change)
1657 {
1658     CYG_REPORT_FUNCNAME("CdlValuable::wizard_update_handler");
1659     CYG_PRECONDITION_CLASSC(transaction);
1660     CYG_PRECONDITION_CLASSC(source);
1661     CYG_PRECONDITION_CLASSC(prop);
1662     
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)) {
1668
1669         CYG_ASSERT_CLASSC(dest);
1670         CdlWizard wizard = dynamic_cast<CdlWizard>(dest);
1671         if (0 == wizard) {
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);
1675         }
1676         
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);
1680     }
1681
1682     CYG_REPORT_RETURN();
1683 }
1684
1685 int
1686 CdlValuableBody::parse_wizard(CdlInterpreter interp, int argc, const char* argv[])
1687 {
1688     CYG_REPORT_FUNCNAMETYPE("parse_wizard", "result %d");
1689
1690     int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Wizard, 0, 0, false, &wizard_update_handler);
1691     CYG_REPORT_RETVAL(result);
1692     return result;
1693 }
1694
1695 bool
1696 CdlValuableBody::has_wizard() const
1697 {
1698     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_wizard", "result %d");
1699     CYG_REPORT_FUNCARG1XV(this);
1700     CYG_PRECONDITION_THISC();
1701
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);
1709
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);
1715             result = true;
1716         }
1717     }
1718     CYG_REPORT_RETVAL(result);
1719     return result;
1720 }
1721
1722 CdlWizard
1723 CdlValuableBody::get_wizard() const
1724 {
1725     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_wizard", "result %p");
1726     CYG_REPORT_FUNCARG1XV(this);
1727     CYG_PRECONDITION_THISC();
1728
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);
1734
1735         CdlNode destination = ref_prop->get_destination();
1736         if (0 != destination) {
1737             result = dynamic_cast<CdlWizard>(destination);
1738             CYG_ASSERTC(0 != result);
1739         }
1740     }
1741
1742     CYG_REPORT_RETVAL(result);
1743     return result;
1744 }
1745
1746 //}}}
1747 //{{{  legal_values property            
1748
1749 // ----------------------------------------------------------------------------
1750 // Syntax: legal_values <list expression>
1751
1752 void
1753 CdlValuableBody::legal_values_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1754                                              CdlUpdate change)
1755 {
1756     CYG_REPORT_FUNCNAME("legal_values_update_handler");
1757
1758     // Loaded and Unloading are of no immediate interest, reference
1759     // updating happens in the calling code.
1760     //
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();
1765         return;
1766     }
1767
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);
1772
1773     valuable->check_value(transaction);
1774
1775     CYG_UNUSED_PARAM(CdlNode, dest);
1776     CYG_UNUSED_PARAM(CdlProperty_ListExpression, lexpr);
1777     CYG_REPORT_RETURN();
1778 }
1779
1780 int
1781 CdlValuableBody::parse_legal_values(CdlInterpreter interp, int argc, const char* argv[])
1782 {
1783     CYG_REPORT_FUNCNAMETYPE("parse_legal_values", "result %d");
1784
1785     int result = CdlParse::parse_listexpression_property(interp, argc, argv, CdlPropertyId_LegalValues, 0, 0,
1786                                                          &legal_values_update_handler);
1787     CYG_REPORT_RETVAL(result);
1788     return result;
1789 }
1790
1791 bool
1792 CdlValuableBody::has_legal_values() const
1793 {
1794     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_legal_values", "result %d");
1795     CYG_REPORT_FUNCARG1XV(this);
1796     CYG_PRECONDITION_THISC();
1797
1798     bool result = has_property(CdlPropertyId_LegalValues);
1799     CYG_REPORT_RETVAL(result);
1800     return result;
1801 }
1802
1803 CdlProperty_ListExpression
1804 CdlValuableBody::get_legal_values() const
1805 {
1806     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_legal_values", "result %p");
1807     CYG_REPORT_FUNCARG1XV(this);
1808     CYG_PRECONDITION_THISC();
1809
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);
1815     }
1816
1817     CYG_REPORT_RETVAL(result);
1818     return result;
1819 }
1820
1821 //}}}
1822 //{{{  default_value property           
1823
1824 // ----------------------------------------------------------------------------
1825 // syntax: default_value <expr>
1826
1827 void
1828 CdlValuableBody::default_value_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1829                                               CdlUpdate change)
1830 {
1831     CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1832     CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1833
1834     // Loaded and unloading should be ignored.
1835     if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1836         CYG_REPORT_RETURN();
1837         return;
1838     }
1839
1840     // Init, Created, Destroyed, ValueChange and ActiveChange should
1841     // all result in the expression being re-evaluated and the result
1842     // applied.
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);
1847     
1848     CdlSimpleValue val;
1849
1850     try {
1851         
1852         CdlEvalContext context(transaction, source, prop);
1853         expr->eval(context, val);
1854
1855         valuable->set(transaction, val, CdlValueSource_Default);
1856
1857     } catch(CdlEvalException e) {
1858
1859         
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
1863         // sensible value.
1864         val = (cdl_int) 0;
1865         valuable->set(transaction, val, CdlValueSource_Default);
1866     }
1867
1868     CYG_UNUSED_PARAM(CdlNode, dest);
1869     CYG_REPORT_RETURN();
1870 }
1871
1872 int
1873 CdlValuableBody::parse_default_value(CdlInterpreter interp, int argc, const char* argv[])
1874 {
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);
1879     return result;
1880 }
1881
1882 bool
1883 CdlValuableBody::has_default_value_expression() const
1884 {
1885     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_default_value_expression", "result %d");
1886     CYG_REPORT_FUNCARG1XV(this);
1887     CYG_PRECONDITION_THISC();
1888
1889     bool result = has_property(CdlPropertyId_DefaultValue);
1890     CYG_REPORT_RETVAL(result);
1891     return result;
1892 }
1893
1894 CdlProperty_Expression
1895 CdlValuableBody::get_default_value_expression() const
1896 {
1897     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_default_value_expression", "result %");
1898     CYG_REPORT_FUNCARG1XV(this);
1899     CYG_PRECONDITION_THISC();
1900
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);
1906     }
1907
1908     CYG_REPORT_RETVAL(result);
1909     return result;
1910 }
1911
1912 //}}}
1913 //{{{  calculated_property              
1914
1915 // ----------------------------------------------------------------------------
1916 // Syntax: calculated <expression>
1917
1918 void
1919 CdlValuableBody::calculated_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1920                                            CdlUpdate change)
1921 {
1922     CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1923     CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1924
1925     // Loaded and unloading should be ignored.
1926     if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1927         CYG_REPORT_RETURN();
1928         return;
1929     }
1930
1931     // Init, Created, Destroyed, ValueChange and ActiveChange should
1932     // all result in the expression being re-evaluated and the result
1933     // applied.
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);
1938     
1939     CdlSimpleValue val;
1940
1941     try {
1942         
1943         CdlEvalContext context(transaction, source, prop);
1944         expr->eval(context, val);
1945
1946         valuable->set(transaction, val, CdlValueSource_Default);
1947
1948     } catch(CdlEvalException e) {
1949
1950         
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
1954         // sensible value.
1955         val = (cdl_int) 0;
1956         valuable->set(transaction, val, CdlValueSource_Default);
1957     }
1958
1959     CYG_UNUSED_PARAM(CdlNode, dest);
1960     CYG_REPORT_RETURN();
1961 }
1962
1963 // FIXME: check for flavor none?
1964 int
1965 CdlValuableBody::parse_calculated(CdlInterpreter interp, int argc, const char* argv[])
1966 {
1967     CYG_REPORT_FUNCNAMETYPE("parse_calculated", "result %d");
1968
1969     int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_Calculated, 0, 0,
1970                                                      &calculated_update_handler);
1971     CYG_REPORT_RETVAL(result);
1972     return result;
1973 }
1974
1975 bool
1976 CdlValuableBody::has_calculated_expression() const
1977 {
1978     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_calculated_expression", "result %d");
1979     CYG_REPORT_FUNCARG1XV(this);
1980     CYG_PRECONDITION_THISC();
1981
1982     bool result = has_property(CdlPropertyId_Calculated);
1983     CYG_REPORT_RETVAL(result);
1984     return result;
1985 }
1986
1987 CdlProperty_Expression
1988 CdlValuableBody::get_calculated_expression() const
1989 {
1990     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_calculated_expression", "result %p");
1991     CYG_REPORT_FUNCARG1XV(this);
1992     CYG_PRECONDITION_THISC();
1993
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);
1999     }
2000
2001     CYG_REPORT_RETVAL(result);
2002     return result;
2003 }
2004
2005 //}}}
2006 //{{{  active_if property               
2007
2008 // ----------------------------------------------------------------------------
2009 // Syntax:
2010 //    active_if <goal expression>
2011
2012 void
2013 CdlValuableBody::active_if_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2014                                       CdlUpdate change)
2015 {
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);
2021
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();
2026         return;
2027     }
2028
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);
2038     }
2039     
2040     CYG_UNUSED_PARAM(CdlNode, dest);
2041     CYG_REPORT_RETURN();
2042 }
2043
2044 int
2045 CdlValuableBody::parse_active_if(CdlInterpreter interp, int argc, const char* argv[])
2046 {
2047     CYG_REPORT_FUNCNAMETYPE("parse_active_if", "result %d");
2048
2049     int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_ActiveIf, 0, 0,
2050                                                          &active_if_update_handler);
2051     CYG_REPORT_RETVAL(result);
2052     return result;
2053 }
2054
2055 bool
2056 CdlValuableBody::has_active_if_conditions() const
2057 {
2058     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_active_if_conditions", "result %d");
2059     CYG_REPORT_FUNCARG1XV(this);
2060     CYG_PRECONDITION_THISC();
2061
2062     bool result = has_property(CdlPropertyId_ActiveIf);
2063     CYG_REPORT_RETVAL(result);
2064     return result;
2065 }
2066
2067 void
2068 CdlValuableBody::get_active_if_conditions(std::vector<CdlProperty_GoalExpression>& result) const
2069 {
2070     CYG_REPORT_FUNCNAME("CdlValuable::get_active_if_conditions");
2071     CYG_REPORT_FUNCARG1XV(this);
2072     CYG_PRECONDITION_THISC();
2073
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);
2081     }
2082
2083     CYG_REPORT_RETURN();
2084 }
2085
2086 //}}}
2087 //{{{  requires property                
2088
2089 // ----------------------------------------------------------------------------
2090 // Syntax: requires <goal expression>
2091
2092 void
2093 CdlValuableBody::requires_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2094                                          CdlUpdate change)
2095 {
2096     CYG_REPORT_FUNCNAME("CdlValuable::requires_update_handler");
2097     CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2098     CYG_PRECONDITION_CLASSC(transaction);
2099
2100     // Loaded and Unloading are not of interest.
2101     if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2102         CYG_REPORT_RETURN();
2103         return;
2104     }
2105     
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);
2113
2114     valuable->check_requires(transaction, gexpr);
2115
2116     CYG_UNUSED_PARAM(CdlNode, dest);
2117     CYG_REPORT_RETURN();
2118 }
2119
2120 int
2121 CdlValuableBody::parse_requires(CdlInterpreter interp, int argc, const char* argv[])
2122 {
2123     CYG_REPORT_FUNCNAMETYPE("parse_requires", "result %d");
2124
2125     int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_Requires, 0, 0,
2126                                                          &requires_update_handler);
2127     CYG_REPORT_RETVAL(result);
2128     return result;
2129 }
2130
2131 bool
2132 CdlValuableBody::has_requires_goals() const
2133 {
2134     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_requires_goals", "result %d");
2135     CYG_REPORT_FUNCARG1XV(this);
2136     CYG_PRECONDITION_THISC();
2137
2138     bool result = has_property(CdlPropertyId_Requires);
2139     CYG_REPORT_RETVAL(result);
2140     return result;
2141 }
2142
2143 void
2144 CdlValuableBody::get_requires_goals(std::vector<CdlProperty_GoalExpression>& result) const
2145 {
2146     CYG_REPORT_FUNCNAME("CdlValuable::get_requires_goals");
2147     CYG_REPORT_FUNCARG1XV(this);
2148     CYG_PRECONDITION_THISC();
2149
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);
2157     }
2158
2159     CYG_REPORT_RETURN();
2160 }
2161
2162 //}}}
2163 //{{{  implements property              
2164
2165 // ----------------------------------------------------------------------------
2166 // Syntax: implements <reference to interface>
2167
2168 void
2169 CdlValuableBody::implements_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2170                                            CdlUpdate change)
2171 {
2172     CYG_REPORT_FUNCNAME("CdlValuable::implements_update_handler");
2173     CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2174     CYG_PRECONDITION_CLASSC(transaction);
2175
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
2182     // future.
2183
2184     // Any changes to the interface itself can be ignored.
2185     if ((CdlUpdate_ValueChange == change) || (CdlUpdate_ActiveChange == change)) {
2186         CYG_REPORT_RETURN();
2187         return;
2188     }
2189
2190     // The second stage init is irrelevant
2191     if (CdlUpdate_Init == change) {
2192         CYG_REPORT_RETURN();
2193         return;
2194     }
2195
2196     // Possibilities:
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
2203     //
2204     // If we have a valid dest, it needs to be updated and any structural
2205     // conflicts have to be cleared.
2206     //
2207     // If there is no dest, the implements property remains unbound.
2208     // A suitable conflict is created in the base class.
2209     //
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.
2213         dest = 0;
2214     }
2215     if (0 == dest) {
2216         transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2217     } else {
2218         CdlInterface interface = dynamic_cast<CdlInterface>(dest);
2219
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);
2224         } else {
2225             transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2226             interface->recalculate(transaction);
2227         }
2228     }
2229     
2230     CYG_REPORT_RETURN();
2231 }
2232
2233 int
2234 CdlValuableBody::parse_implements(CdlInterpreter interp, int argc, const char* argv[])
2235 {
2236     CYG_REPORT_FUNCNAMETYPE("parse_implements", "result %d");
2237
2238     int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Implements, 0, 0, false,
2239                                                     &implements_update_handler);
2240     
2241     CYG_REPORT_RETVAL(result);
2242     return result;
2243 }
2244
2245 void
2246 CdlValuableBody::get_implemented_interfaces(std::vector<CdlInterface>& result) const
2247 {
2248     CYG_REPORT_FUNCNAME("CdlValuable::get_implemented_interfaces");
2249     CYG_REPORT_FUNCARG1XV(this);
2250     CYG_PRECONDITION_THISC();
2251
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();
2259         if (0 != node) {
2260             CdlInterface interface = dynamic_cast<CdlInterface>(node);
2261             CYG_ASSERT_CLASSC(interface);
2262             result.push_back(interface);
2263         }
2264     }
2265
2266     CYG_REPORT_RETURN();
2267 }
2268
2269 //}}}
2270 //{{{  Other properties                 
2271
2272 // ----------------------------------------------------------------------------
2273 // Syntax: flavor <legal flavor>
2274
2275 static void
2276 parse_flavor_final_check(CdlInterpreter interp, CdlProperty_String prop)
2277 {
2278     CYG_REPORT_FUNCNAME("parse_flavor_final_check");
2279     CYG_PRECONDITION_CLASSC(interp);
2280     CYG_PRECONDITION_CLASSC(prop);
2281     
2282     const std::string& str = prop->get_string();
2283     std::string copy = std::string(str);
2284     CdlValueFlavor flavor;
2285
2286     if (!Cdl::string_to_flavor(copy, flavor)) {
2287         CdlParse::report_property_parse_error(interp, prop, str + " is not a valid CDL flavor.");
2288     }
2289     
2290     CYG_REPORT_RETURN();
2291 }
2292
2293
2294 int
2295 CdlValuableBody::parse_flavor(CdlInterpreter interp, int argc, const char* argv[])
2296 {
2297     CYG_REPORT_FUNCNAMETYPE("parse_flavor", "result %d");
2298
2299     int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Flavor, 0, &parse_flavor_final_check);
2300     CYG_REPORT_RETVAL(result);
2301     return result;
2302 }
2303
2304 // ----------------------------------------------------------------------------
2305 // syntax: group <group name>
2306 int
2307 CdlValuableBody::parse_group(CdlInterpreter interp, int argc, const char* argv[])
2308 {
2309     CYG_REPORT_FUNCNAMETYPE("parse_group", "result %d");
2310
2311     int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Group, 0, 0);
2312     
2313     CYG_REPORT_RETVAL(result);
2314     return result;
2315 }
2316
2317 // ----------------------------------------------------------------------------
2318 // Syntax: check_proc <tclcode>
2319
2320 int
2321 CdlValuableBody::parse_check_proc(CdlInterpreter interp, int argc, const char* argv[])
2322 {
2323     CYG_REPORT_FUNCNAMETYPE("parse_check_proc", "result %d");
2324
2325     int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_CheckProc, 0, 0);
2326     
2327     CYG_REPORT_RETVAL(result);
2328     return result;
2329 }
2330
2331 bool
2332 CdlValuableBody::has_check_proc() const
2333 {
2334     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_check_proc", "result %d");
2335     CYG_REPORT_FUNCARG1XV(this);
2336     CYG_PRECONDITION_THISC();
2337
2338     bool result = has_property(CdlPropertyId_CheckProc);
2339     CYG_REPORT_RETVAL(result);
2340     return result;
2341 }
2342
2343 cdl_tcl_code
2344 CdlValuableBody::get_check_proc() const
2345 {
2346     CYG_REPORT_FUNCNAME("CdlValuable::get_check_proc");
2347     CYG_REPORT_FUNCARG1XV(this);
2348     CYG_PRECONDITION_THISC();
2349
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();
2356     }
2357     
2358     CYG_REPORT_RETURN();
2359     return result;
2360 }
2361
2362 // ----------------------------------------------------------------------------
2363 // Syntax: entry_proc <tclcode>
2364
2365 int
2366 CdlValuableBody::parse_entry_proc(CdlInterpreter interp, int argc, const char* argv[])
2367 {
2368     CYG_REPORT_FUNCNAMETYPE("parse_entry_proc", "result %d");
2369
2370     int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_EntryProc, 0, 0);
2371     
2372     CYG_REPORT_RETVAL(result);
2373     return result;
2374 }
2375
2376 bool
2377 CdlValuableBody::has_entry_proc() const
2378 {
2379     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_entry_proc", "result %d");
2380     CYG_REPORT_FUNCARG1XV(this);
2381     CYG_PRECONDITION_THISC();
2382
2383     bool result = has_property(CdlPropertyId_EntryProc);
2384     CYG_REPORT_RETVAL(result);
2385     return result;
2386 }
2387 cdl_tcl_code
2388 CdlValuableBody::get_entry_proc() const
2389 {
2390     CYG_REPORT_FUNCNAME("CdlValuable::get_entry_proc");
2391     CYG_REPORT_FUNCARG1XV(this);
2392     CYG_PRECONDITION_THISC();
2393
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();
2400     }
2401
2402     CYG_REPORT_RETURN();
2403     return result;
2404 }
2405
2406 //}}}
2407
2408 //{{{  CdlValuable misc                 
2409
2410 // ----------------------------------------------------------------------------
2411 // Objects with flavor none are not modifiable. Also, objects with the
2412 // calculated property are not modifiable. Everything else is ok.
2413
2414 bool
2415 CdlValuableBody::is_modifiable() const
2416 {
2417     CYG_REPORT_FUNCNAMETYPE("CdlValuableBody::is_modifiable", "result %d");
2418     CYG_REPORT_FUNCARG1XV(this);
2419     CYG_PRECONDITION_THISC();
2420
2421     bool result = true;
2422     if (CdlValueFlavor_None == get_flavor()) {
2423         result = false;
2424     } else if (has_property(CdlPropertyId_Calculated)) {
2425         result = false;
2426     }
2427
2428     CYG_REPORT_RETVAL(result);
2429     return result;
2430 }
2431
2432 //}}}
2433 //{{{  CdlValuable::get_widget_hint()   
2434
2435 // ----------------------------------------------------------------------------
2436
2437 void
2438 CdlValuableBody::get_widget_hint(CdlWidgetHint& hint)
2439 {
2440     CYG_REPORT_FUNCNAME("CdlValuable::get_widget_hint");
2441     CYG_REPORT_FUNCARG2XV(this, &hint);
2442     CYG_PRECONDITION_THISC();
2443
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 = "";
2448
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();
2457         return;
2458     }
2459     
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();
2464         return;
2465     }
2466
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;
2471         }
2472         if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2473             hint.value_widget = CdlValueWidget_CustomDialog;
2474         }
2475         CYG_REPORT_RETURN();
2476         return;
2477     }
2478     
2479     // Process the bool part, if any
2480     if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2481         
2482         // Default to a CheckButton
2483         hint.bool_widget = CdlBoolWidget_CheckButton;
2484
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:
2490         //
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.
2494         //
2495         // 2) external packages. It should be possible to have a third party package
2496         //    which could add e.g. a new scheduler.
2497         //
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);
2509
2510             CdlNode destnode = refprop->get_destination();
2511             if (0 == destnode) {
2512                 continue;
2513             }
2514             CdlInterface interface = dynamic_cast<CdlInterface>(destnode);
2515             CYG_ASSERT_CLASSC(interface);
2516  
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++) {
2521
2522                 CdlExpression expr = (*req_i)->get_expression();
2523                 CdlSubexpression& subexpr = expr->sub_expressions[expr->first_subexpression];
2524                 if (CdlExprOp_Equal != subexpr.op) {
2525                     continue;
2526                 }
2527  
2528                 CdlSubexpression& lhs = expr->sub_expressions[subexpr.lhs_index];
2529                 CdlSubexpression& rhs = expr->sub_expressions[subexpr.rhs_index];
2530                 CdlSubexpression* ref_operand = &lhs;
2531
2532                 // Allow for "a == 1" or "1 == a"
2533                 if ((CdlExprOp_IntegerConstant == lhs.op) && (1 == lhs.constants.get_integer_value())) {
2534                     ref_operand = &rhs;
2535                 } else if ((CdlExprOp_IntegerConstant == rhs.op) && (1 == rhs.constants.get_integer_value())) {
2536                     ref_operand = &lhs;
2537                 } else {
2538                     continue;
2539                 }
2540
2541                 if (CdlExprOp_Reference != ref_operand->op) {
2542                     continue;
2543                 }
2544                 CdlReference& ref = expr->references[ref_operand->reference_index];
2545                 if (ref.get_destination() == interface) {
2546                     break;
2547                 }
2548             }
2549             if (req_i == requires.end()) {
2550                 continue;
2551             }
2552
2553             CdlContainer parent = this->get_parent();
2554             CYG_ASSERT_CLASSC(parent);
2555  
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()) {
2561                     break;
2562                 }
2563             }
2564
2565             if (imp_i == implementers.end()) {
2566                 // An interface has been found that matches the constraints.
2567                 radio_interface = interface;
2568             }
2569         }
2570         if (0 != radio_interface) {
2571             hint.bool_widget = CdlBoolWidget_Radio;
2572             hint.radio_button_interface = radio_interface->get_name();
2573         }
2574     }
2575
2576     // Process the data part, if any
2577     if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2578         
2579         // Default to a simple entry box.
2580         hint.value_widget = CdlValueWidget_EntryBox;
2581         
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);
2594             CdlListValue               val;
2595
2596             try {
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();
2601                 
2602                 if ((0 == table.size()) && (0 == int_ranges.size()) && (1 == double_ranges.size())) {
2603                     
2604                     // A straightforward range of double precision numbers
2605                     hint.value_widget = CdlValueWidget_DoubleRange;
2606                     
2607                 } else if ((0 == table.size()) && (1 == int_ranges.size()) && (0 == double_ranges.size())) {
2608
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;
2613                     
2614                 } else if ((1 <= table.size() && (0 == int_ranges.size()) && (0 == double_ranges.size()))) {
2615
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;
2623                         }
2624                     }
2625                     if (all_numeric) {
2626                         hint.value_widget = CdlValueWidget_NumericSet;
2627                     } else {
2628                         hint.value_widget = CdlValueWidget_StringSet;
2629                     }
2630                     
2631                 } else {
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.
2637                 }
2638                 
2639             } catch(...) {
2640                 // Not a lot that can be done here, unfortunately
2641             }
2642         } else {
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);
2649                 CdlSimpleValue         val;
2650                 try {
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;
2655                     }
2656                 } catch(...) {
2657                     // Not a lot that can be done here, unfortunately
2658                 }
2659             }
2660         }
2661     }
2662     
2663     CYG_REPORT_RETURN();
2664 }
2665
2666 //}}}
2667 //{{{  CdlValuable get operations       
2668
2669 // ----------------------------------------------------------------------------
2670 const CdlValue&
2671 CdlValuableBody::get_whole_value() const
2672 {
2673     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_whole_value", "result %p");
2674     CYG_REPORT_FUNCARG1XV(this);
2675     CYG_PRECONDITION_THISC();
2676
2677     CYG_REPORT_RETVAL(&value);
2678     return value;
2679 }
2680
2681 CdlValueFlavor
2682 CdlValuableBody::get_flavor() const
2683 {
2684     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_flavor", "result %d");
2685     CYG_REPORT_FUNCARG1XV(this);
2686     CYG_PRECONDITION_THISC();
2687
2688     CdlValueFlavor result = value.get_flavor();
2689     CYG_REPORT_RETVAL((int) result);
2690     return result;
2691 }
2692
2693 CdlValueSource
2694 CdlValuableBody::get_source() const
2695 {
2696     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2697     CYG_REPORT_FUNCARG1XV(this);
2698     CYG_PRECONDITION_THISC();
2699
2700     CdlValueSource result = value.get_source();
2701     CYG_REPORT_RETVAL((int) result);
2702     return result;
2703 }
2704
2705 bool
2706 CdlValuableBody::has_source(CdlValueSource source) const
2707 {
2708     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2709     CYG_REPORT_FUNCARG2XV(this, source);
2710     CYG_PRECONDITION_THISC();
2711
2712     bool result = value.has_source(source);
2713     CYG_REPORT_RETVAL(result);
2714     return result;
2715 }
2716
2717 bool
2718 CdlValuableBody::is_enabled(CdlValueSource source) const
2719 {
2720     CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2721     CYG_REPORT_FUNCARG2XV(this, source);
2722     CYG_PRECONDITION_THISC();
2723
2724     bool result = value.is_enabled(source);
2725     CYG_REPORT_RETVAL(result);
2726     return result;
2727 }
2728
2729 std::string
2730 CdlValuableBody::get_value(CdlValueSource source) const
2731 {
2732     CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2733     CYG_REPORT_FUNCARG2XV(this, source);
2734     CYG_PRECONDITION_THISC();
2735
2736     std::string result = value.get_value(source);
2737     CYG_REPORT_RETURN();
2738     return result;
2739 }
2740
2741 bool
2742 CdlValuableBody::has_integer_value(CdlValueSource source) const
2743 {
2744     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2745     CYG_REPORT_FUNCARG2XV(this, source);
2746     CYG_PRECONDITION_THISC();
2747
2748     bool result = value.has_integer_value(source);
2749     CYG_REPORT_RETVAL(result);
2750     return result;
2751 }
2752
2753 cdl_int
2754 CdlValuableBody::get_integer_value(CdlValueSource source) const
2755 {
2756     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2757     CYG_REPORT_FUNCARG2XV(this, source);
2758     CYG_PRECONDITION_THISC();
2759
2760     cdl_int result = value.get_integer_value(source);
2761     CYG_REPORT_RETVAL((int) result);
2762     return result;
2763 }
2764
2765 bool
2766 CdlValuableBody::has_double_value(CdlValueSource source) const
2767 {
2768     CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2769     CYG_REPORT_FUNCARG2XV(this, source);
2770     CYG_PRECONDITION_THISC();
2771
2772     bool result = value.has_double_value(source);
2773     CYG_REPORT_RETVAL(result);
2774     return result;
2775 }
2776
2777 double
2778 CdlValuableBody::get_double_value(CdlValueSource source) const
2779 {
2780     CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2781     CYG_REPORT_FUNCARG2XV(this, source);
2782     CYG_PRECONDITION_THISC();
2783
2784     double result = value.get_double_value();
2785     CYG_REPORT_RETURN();
2786     return result;
2787 }
2788
2789 CdlSimpleValue
2790 CdlValuableBody::get_simple_value(CdlValueSource source) const
2791 {
2792     CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2793     CYG_REPORT_FUNCARG2XV(this, source);
2794     CYG_PRECONDITION_THISC();
2795
2796     CdlSimpleValue result = value.get_simple_value(source);
2797     CYG_REPORT_RETURN();
2798     return result;
2799 }
2800
2801 // ----------------------------------------------------------------------------
2802 CdlValueSource
2803 CdlValuableBody::get_source(CdlTransaction transaction) const
2804 {
2805     CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2806     CYG_REPORT_FUNCARG2XV(this, transaction);
2807     CYG_PRECONDITION_THISC();
2808     CYG_PRECONDITION_CLASSC(transaction);
2809
2810     const CdlValue& transaction_value = transaction->get_whole_value(this);
2811     CdlValueSource result = transaction_value.get_source();
2812     CYG_REPORT_RETVAL((int) result);
2813     return result;
2814 }
2815
2816 bool
2817 CdlValuableBody::has_source(CdlTransaction transaction, CdlValueSource source) const
2818 {
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);
2823
2824     const CdlValue& transaction_value = transaction->get_whole_value(this);
2825     bool result = transaction_value.has_source(source);
2826     CYG_REPORT_RETVAL(result);
2827     return result;
2828 }
2829
2830 bool
2831 CdlValuableBody::is_enabled(CdlTransaction transaction, CdlValueSource source) const
2832 {
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);
2837
2838     const CdlValue& transaction_value = transaction->get_whole_value(this);
2839     bool result = transaction_value.is_enabled(source);
2840     CYG_REPORT_RETVAL(result);
2841     return result;
2842 }
2843
2844 std::string
2845 CdlValuableBody::get_value(CdlTransaction transaction, CdlValueSource source) const
2846 {
2847     CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2848     CYG_REPORT_FUNCARG3XV(this, transaction, source);
2849     CYG_PRECONDITION_THISC();
2850     CYG_PRECONDITION_CLASSC(transaction);
2851
2852     const CdlValue& transaction_value = transaction->get_whole_value(this);
2853     std::string result = transaction_value.get_value(source);
2854     CYG_REPORT_RETURN();
2855     return result;
2856 }
2857
2858 bool
2859 CdlValuableBody::has_integer_value(CdlTransaction transaction, CdlValueSource source) const
2860 {
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);
2865
2866     const CdlValue& transaction_value = transaction->get_whole_value(this);
2867     bool result = transaction_value.has_integer_value(source);
2868     CYG_REPORT_RETVAL(result);
2869     return result;
2870 }
2871
2872 cdl_int
2873 CdlValuableBody::get_integer_value(CdlTransaction transaction, CdlValueSource source) const
2874 {
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);
2879
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);
2883     return result;
2884 }
2885
2886 bool
2887 CdlValuableBody::has_double_value(CdlTransaction transaction, CdlValueSource source) const
2888 {
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);
2893
2894     const CdlValue& transaction_value = transaction->get_whole_value(this);
2895     bool result = transaction_value.has_double_value(source);
2896     CYG_REPORT_RETVAL(result);
2897     return result;
2898 }
2899
2900 double
2901 CdlValuableBody::get_double_value(CdlTransaction transaction, CdlValueSource source) const
2902 {
2903     CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2904     CYG_REPORT_FUNCARG3XV(this, transaction, source);
2905     CYG_PRECONDITION_THISC();
2906     CYG_PRECONDITION_CLASSC(transaction);
2907
2908     const CdlValue& transaction_value = transaction->get_whole_value(this);
2909     double result = transaction_value.get_double_value();
2910     CYG_REPORT_RETURN();
2911     return result;
2912 }
2913
2914 CdlSimpleValue
2915 CdlValuableBody::get_simple_value(CdlTransaction transaction, CdlValueSource source) const
2916 {
2917     CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2918     CYG_REPORT_FUNCARG3XV(this, transaction, source);
2919     CYG_PRECONDITION_THISC();
2920     CYG_PRECONDITION_CLASSC(transaction);
2921
2922     const CdlValue& transaction_value = transaction->get_whole_value(this);
2923     CdlSimpleValue result = transaction_value.get_simple_value(source);
2924     CYG_REPORT_RETURN();
2925     return result;
2926 }
2927
2928 //}}}
2929 //{{{  CdlValuable internal modify ops  
2930
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.
2935 void
2936 CdlValuableBody::check_value(CdlTransaction transaction)
2937 {
2938     CYG_REPORT_FUNCNAME("CdlValuable::check_value");
2939     CYG_REPORT_FUNCARG2XV(this, transaction);
2940     CYG_PRECONDITION_THISC();
2941     CYG_PRECONDITION_CLASSC(transaction);
2942
2943     // Checking the value only makes sense for BoolData and Data
2944     // values.
2945     CdlValueFlavor flavor = value.get_flavor();
2946     if ((CdlValueFlavor_BoolData != flavor) && (CdlValueFlavor_Data != flavor)) {
2947         CYG_REPORT_RETURN();
2948         return;
2949     }
2950
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();
2957         return;
2958     }
2959
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);
2964
2965         CdlSimpleValue val = this->get_simple_value(transaction);
2966         CdlEvalContext context(transaction, this, lexpr);
2967         try {
2968             if (!lexpr->is_member(context, val)) {
2969                 if (!transaction->has_conflict(this, lexpr, &CdlConflict_IllegalValueBody::test)) {
2970                     CdlConflict_IllegalValueBody::make(transaction, this, lexpr);
2971                 }
2972             
2973             } else {
2974                 // Tne current value is legal. Get rid of any old conflicts.
2975                 transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2976             }
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
2980             // as well.
2981             transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2982         }              
2983
2984         // FIXME: add support for check_proc
2985     }
2986     
2987     CYG_REPORT_RETURN();
2988 }
2989
2990 // ----------------------------------------------------------------------------
2991 // There has been a change that may affect "requires" properties.
2992 // Again do the necessary checking and maintain suitable conflict
2993 // objects.
2994 void
2995 CdlValuableBody::check_requires(CdlTransaction transaction)
2996 {
2997     CYG_REPORT_FUNCNAME("CdlValuable::check_requires");
2998     CYG_REPORT_FUNCARG2XV(this, transaction);
2999     CYG_PRECONDITION_THISC();
3000     CYG_PRECONDITION_CLASSC(transaction);
3001
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++) {
3006
3007         CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3008         CYG_ASSERT_CLASSC(gexpr);
3009         this->check_requires(transaction, gexpr);
3010     }
3011
3012     CYG_REPORT_RETURN();
3013 }
3014
3015 void
3016 CdlValuableBody::check_requires(CdlTransaction transaction, CdlProperty_GoalExpression gexpr)
3017 {
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);
3023
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();
3029         return;
3030     }
3031
3032     // What is the current value of the goal expression?
3033     try {
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);
3038         } else {
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);
3042             }
3043         }
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);
3048     }
3049     
3050     CYG_REPORT_RETURN();
3051 }
3052
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.
3057 void
3058 CdlValuableBody::update(CdlTransaction transaction, CdlUpdate update)
3059 {
3060     CYG_REPORT_FUNCNAME("CdlValuable::update");
3061     CYG_REPORT_FUNCARG3XV(this, transaction, update);
3062     CYG_PRECONDITION_THISC();
3063     CYG_PRECONDITION_CLASSC(transaction);
3064
3065     if ((CdlUpdate_ValueChange == update) || (CdlUpdate_ActiveChange == update)) {
3066         this->check_value(transaction);
3067         this->check_requires(transaction);
3068     }
3069     
3070     CYG_REPORT_RETURN();
3071 }
3072
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
3076 // to be evaluated.
3077
3078 bool
3079 CdlValuableBody::test_active(CdlTransaction transaction)
3080 {
3081     CYG_REPORT_FUNCNAMETYPE("CdlValuable::test_active", "result %d");
3082     CYG_REPORT_FUNCARG2XV(this, transaction);
3083     CYG_PRECONDITION_THISC();
3084     CYG_PRECONDITION_CLASSC(transaction);
3085
3086     bool result = true;
3087     if (!this->CdlNodeBody::test_active(transaction)) {
3088         result = false;
3089     }
3090
3091     if (result) {
3092         std::vector<CdlProperty> active_if_properties;
3093         std::vector<CdlProperty>::const_iterator prop_i;
3094         
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++) {
3097             
3098             CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3099             CYG_ASSERT_CLASSC(gexpr);
3100             CdlEvalContext context(transaction, this, gexpr);
3101             try {
3102                 if (!gexpr->eval(context)) {
3103                     result = false;
3104                 }
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.
3111             }
3112         }
3113     }
3114
3115     CYG_REPORT_RETVAL(result);
3116     return result;
3117 }
3118
3119 //}}}
3120 //{{{  CdlValuable modify operations    
3121
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.
3126
3127 void
3128 CdlValuableBody::set_source(CdlValueSource source)
3129 {
3130     CYG_REPORT_FUNCNAME("CdlValuable::set_source (no transaction)");
3131     CYG_REPORT_FUNCARG2XV(this, source);
3132     CYG_PRECONDITION_THISC();
3133     
3134     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3135     this->set_source(transaction, source);
3136     transaction->body();
3137     delete transaction;
3138
3139     CYG_REPORT_RETURN();
3140 }
3141
3142 void
3143 CdlValuableBody::invalidate_source(CdlValueSource source)
3144 {
3145     CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source (no transaction)");
3146     CYG_REPORT_FUNCARG2XV(this, source);
3147     CYG_PRECONDITION_THISC();
3148
3149     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3150     this->invalidate_source(transaction, source);
3151     transaction->body();
3152     delete transaction;
3153
3154     CYG_REPORT_RETURN();
3155 }
3156
3157 void
3158 CdlValuableBody::set_enabled(bool val, CdlValueSource source)
3159 {
3160     CYG_REPORT_FUNCNAME("CdlValuable::set_enabled (no transaction)");
3161     CYG_REPORT_FUNCARG3XV(this, val, source);
3162     CYG_PRECONDITION_THISC();
3163     
3164     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3165     this->set_enabled(transaction, val, source);
3166     transaction->body();
3167     delete transaction;
3168
3169     CYG_REPORT_RETURN();
3170 }
3171
3172 void
3173 CdlValuableBody::set_value(CdlSimpleValue& val, CdlValueSource source)
3174 {
3175     CYG_REPORT_FUNCNAME("CdlValuable::set_value (no transaction)");
3176     CYG_REPORT_FUNCARG3XV(this, &val, source);
3177     CYG_PRECONDITION_THISC();
3178
3179     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3180     this->set_value(transaction, val, source);
3181     transaction->body();
3182     delete transaction;
3183
3184     CYG_REPORT_RETURN();
3185 }
3186
3187 void
3188 CdlValuableBody::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
3189 {
3190     CYG_REPORT_FUNCNAME("CdlValuable::set_enabled_and_value (no transaction)");
3191     CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
3192     CYG_PRECONDITION_THISC();
3193
3194     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3195     this->set_enabled_and_value(transaction, enabled_arg, val, source);
3196     transaction->body();
3197     delete transaction;
3198
3199     CYG_REPORT_RETURN();
3200 }
3201
3202 void
3203 CdlValuableBody::set(CdlSimpleValue& val, CdlValueSource source)
3204 {
3205     CYG_REPORT_FUNCNAME("CdlValuable::set (no transaction)");
3206     CYG_REPORT_FUNCARG3XV(this, &val, source);
3207     CYG_PRECONDITION_THISC();
3208
3209     CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3210     this->set(transaction, val, source);
3211     transaction->body();
3212     delete transaction;
3213
3214     CYG_REPORT_RETURN();
3215 }
3216
3217 // ----------------------------------------------------------------------------
3218 // These member functions operate in the context of a transaction. The
3219 // basic format is:
3220 //
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.
3224 //
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.
3228
3229 void
3230 CdlValuableBody::set_source(CdlTransaction transaction, CdlValueSource source)
3231 {
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);
3237     
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);
3242
3243     CYG_REPORT_RETURN();
3244 }
3245
3246 void
3247 CdlValuableBody::invalidate_source(CdlTransaction transaction, CdlValueSource source)
3248 {
3249     CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source");
3250     CYG_REPORT_FUNCARG3XV(this, transaction, source);
3251     CYG_PRECONDITION_THISC();
3252     CYG_PRECONDITION_CLASSC(transaction);
3253     
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);
3258     
3259     CYG_REPORT_RETURN();
3260 }
3261
3262 void
3263 CdlValuableBody::set_enabled(CdlTransaction transaction, bool enabled_arg, CdlValueSource source)
3264 {
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);
3270
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);
3275     
3276     CYG_REPORT_RETURN();
3277 }
3278
3279 void
3280 CdlValuableBody::set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3281 {
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);
3287     
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);
3292     
3293     CYG_REPORT_RETURN();
3294 }
3295
3296 void
3297 CdlValuableBody::set_enabled_and_value(CdlTransaction transaction, bool enabled_arg, CdlSimpleValue& val,
3298                                        CdlValueSource source)
3299 {
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);
3305     
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);
3310     
3311     CYG_REPORT_RETURN();
3312 }
3313
3314 void
3315 CdlValuableBody::set(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3316 {
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);
3322     
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);
3327     
3328     CYG_REPORT_RETURN();
3329 }
3330
3331 void
3332 CdlValuableBody::set(CdlTransaction transaction, const CdlValue& val)
3333 {
3334     CYG_REPORT_FUNCNAME("CdlValuable::set");
3335     CYG_REPORT_FUNCARG2XV(this, transaction);
3336     CYG_PRECONDITION_THISC();
3337     CYG_PRECONDITION_CLASSC(transaction);
3338     
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);
3342
3343     CYG_REPORT_RETURN();
3344 }
3345
3346 //}}}
3347 //{{{  CdlValuable basics               
3348
3349 // ----------------------------------------------------------------------------
3350 // The CdlValuable class implements the concept of CDL objects that take
3351 // a value. There are lots of properties associated with that.
3352
3353 CdlValuableBody::CdlValuableBody(CdlValueFlavor flavor)
3354     : value(flavor)
3355 {
3356     CYG_REPORT_FUNCNAME("CdlValuable:: default constructor");
3357     CYG_REPORT_FUNCARG1XV(this);
3358
3359     cdlvaluablebody_cookie = CdlValuableBody_Magic;
3360     CYGDBG_MEMLEAK_CONSTRUCTOR();
3361     
3362     CYG_POSTCONDITION_THISC();
3363     CYG_REPORT_RETURN();
3364 }
3365
3366 CdlValuableBody::~CdlValuableBody()
3367 {
3368     CYG_REPORT_FUNCNAME("CdlValuableBody:: destructor");
3369     CYG_REPORT_FUNCARG1XV(this);
3370     CYG_PRECONDITION_THISC();
3371
3372     cdlvaluablebody_cookie = CdlValuableBody_Invalid;
3373     CYGDBG_MEMLEAK_DESTRUCTOR();
3374     
3375     CYG_REPORT_RETURN();
3376 }
3377
3378 // ----------------------------------------------------------------------------
3379
3380 std::string
3381 CdlValuableBody::get_class_name() const
3382 {
3383     CYG_REPORT_FUNCNAME("CdlValuable::get_class_name");
3384     CYG_PRECONDITION_THISC();
3385     CYG_REPORT_RETURN();
3386     return "valuable";
3387 }
3388
3389 // ----------------------------------------------------------------------------
3390 bool
3391 CdlValuableBody::check_this(cyg_assert_class_zeal zeal) const
3392 {
3393     if (CdlValuableBody_Magic != cdlvaluablebody_cookie) {
3394         return false;
3395     }
3396     CYGDBG_MEMLEAK_CHECKTHIS();
3397
3398     if (has_property(CdlPropertyId_Calculated) && (CdlValueSource_Default != value.get_source())) {
3399         CYG_FAIL("Calculated valuables can only have a default value.");
3400         return false;
3401     }
3402     
3403     return CdlNodeBody::check_this(zeal) && value.check_this(zeal);
3404 }
3405
3406 //}}}
3407 //{{{  CdlValuable parsing support      
3408
3409 // ----------------------------------------------------------------------------
3410 // Parsing support. Adding the appropriate parsers is straightforward.
3411
3412 void
3413 CdlValuableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
3414 {
3415     CYG_REPORT_FUNCNAME("CdlValuable::add_property_parsers");
3416
3417     static CdlInterpreterCommandEntry commands[] =
3418     {
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                   )
3432     };
3433
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");
3440                 }
3441                 break;
3442             }
3443         }
3444         if (j == parsers.end()) {
3445             parsers.push_back(commands[i]);
3446         }
3447     }
3448     CdlNodeBody::add_property_parsers(parsers);
3449     
3450     CYG_REPORT_RETURN();
3451 }
3452
3453 // Validatation is quite a bit more complicated...
3454 void
3455 CdlValuableBody::check_properties(CdlInterpreter interp)
3456 {
3457     CYG_REPORT_FUNCNAME("CdlValuable::check_properties");
3458     CYG_REPORT_FUNCARG2XV(this, interp);
3459     CYG_PRECONDITION_THISC();
3460     CYG_PRECONDITION_CLASSC(interp);
3461
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.");
3470     }
3471     if (count_properties(CdlPropertyId_EntryProc) > 1) {
3472         CdlParse::report_error(interp, "", "There should be at most one entry_proc property.");
3473     }
3474     if (count_properties(CdlPropertyId_CheckProc) > 1) {
3475         CdlParse::report_error(interp, "", "There should be at most one check_proc property.");
3476     }
3477     if (count_properties(CdlPropertyId_DefaultValue) > 1) {
3478         CdlParse::report_error(interp, "", "There should be at most one default_value property.");
3479     }
3480     if (count_properties(CdlPropertyId_LegalValues) > 1) {
3481         CdlParse::report_error(interp, "", "There should be at most one legal_values property.");
3482     }
3483     if (count_properties(CdlPropertyId_Dialog) > 1) {
3484         CdlParse::report_error(interp, "", "There should be at most one dialog property.");
3485     }
3486     if (count_properties(CdlPropertyId_Wizard) > 1) {
3487         CdlParse::report_error(interp, "", "There should be at most one wizard property.");
3488     }
3489     if (count_properties(CdlPropertyId_Calculated) > 1) {
3490         CdlParse::report_error(interp, "", "There should be at most one calculated property.");
3491     }
3492
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);
3497         
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);
3503         } else {
3504             value.set_flavor(flavor);
3505         }
3506
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
3512     }
3513
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.
3518     //
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."); 
3524         }
3525     }
3526
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.");
3530     }
3531
3532 #if 0
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
3536     // applicable.
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.");
3539     }
3540 #endif    
3541
3542     // All of the expressions may be invalid because of unresolved references,
3543     // ditto for implements and for dialog. 
3544     
3545     CdlNodeBody::check_properties(interp);
3546     
3547     CYG_REPORT_RETURN();
3548 }
3549
3550 //}}}
3551 //{{{  CdlValuable persistence support  
3552
3553 // ----------------------------------------------------------------------------
3554 void
3555 CdlValuableBody::initialize_savefile_support(CdlToplevel toplevel, std::string major_command)
3556 {
3557     CYG_REPORT_FUNCNAME("CdlValuable::initialize_savefile_support");
3558     CYG_PRECONDITION_CLASSC(toplevel);
3559     CYG_PRECONDITIONC("" != major_command);
3560
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);
3565
3566     CYG_REPORT_RETURN();
3567 }
3568
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
3572 // a default value.
3573 bool
3574 CdlValuableBody::value_savefile_entry_needed() const
3575 {
3576     CYG_REPORT_FUNCNAMETYPE("CdlValuable::value_savefile_entry_needed", "result %d");
3577     CYG_REPORT_FUNCARG1XV(this);
3578     CYG_PRECONDITION_THISC();
3579
3580     bool result = false;
3581
3582     if (this->is_modifiable()) {
3583         if (this->has_source(CdlValueSource_User) ||
3584             this->has_source(CdlValueSource_Wizard) ||
3585             this->has_source(CdlValueSource_Inferred)) {
3586
3587             result = true;
3588         }
3589     }
3590     
3591     CYG_REPORT_RETVAL(result);
3592     return result;
3593 }
3594
3595 // ----------------------------------------------------------------------------
3596 // This utility is useful for outputting a particular value source
3597
3598 static std::string one    = "1";     // Needed to avoid confusing the compiler
3599 static std::string zero   = "0";
3600
3601 static std::string
3602 value_to_string(CdlValuable valuable, CdlValueSource source)
3603 {
3604     CYG_REPORT_FUNCNAME("value_to_string");
3605
3606     std::string data = "";
3607     
3608     switch(valuable->get_flavor()) {
3609       case CdlValueFlavor_Bool :
3610         data += (valuable->is_enabled(source) ? one : zero);
3611         break;
3612       case CdlValueFlavor_BoolData :
3613         data += (valuable->is_enabled(source) ? one : zero) + " " +
3614             CdlInterpreterBody::quote(valuable->get_value(source));
3615         break;
3616       case CdlValueFlavor_Data:
3617         data += CdlInterpreterBody::quote(valuable->get_value(source));
3618         break;
3619       default:
3620         CYG_FAIL("Invalid value flavor detected");
3621         break;
3622     }
3623     return data;
3624 }
3625
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)
3630 {
3631     CYG_REPORT_FUNCNAMETYPE("get_expected_source", "result %d");
3632     CYG_REPORT_FUNCARG1XV(valuable);
3633
3634     CdlValueSource expected_source = CdlValueSource_Default;
3635         
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;
3642     }
3643
3644     CYG_REPORT_RETVAL((int) expected_source);
3645     return expected_source;
3646 }
3647
3648 // And another utility, to list the valuables listed in an expression.
3649 // e.g. for an expression of the form
3650 //
3651 //      requires (AAA + BBB) > CCC
3652 //
3653 // this would produce:
3654 //
3655 //      AAA == 1
3656 //      BBB == 2
3657 //      CCC == 0
3658 //
3659 // No indentation happens here, instead the calling code is assumed
3660 // to use multiline_comment()
3661 static std::string
3662 follow_expr_references(CdlProperty property, CdlExpression expr)
3663 {
3664     CYG_REPORT_FUNCNAME("follow_expr_references");
3665     CYG_REPORT_FUNCARG1XV(expr);
3666     CYG_PRECONDITION_CLASSC(expr);
3667
3668     std::string    data = "";
3669     CdlSimpleValue simple_value;
3670     std::vector<CdlReference>::const_iterator ref_i;
3671     
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;
3676         if (0 != refnode) {
3677             refvaluable = dynamic_cast<CdlValuable>(refnode);
3678         }
3679         data += refname + " ";
3680         if (0 == refvaluable) {
3681             data += "(unknown) == 0";
3682         } else {
3683             CdlEvalContext context(0, refvaluable, property);
3684             CdlSimpleValue::eval_valuable(context, refvaluable, simple_value);
3685             data += "== " + CdlInterpreterBody::quote(simple_value.get_value());
3686         }
3687         data += '\n';
3688     }
3689     
3690     CYG_REPORT_RETURN();
3691     return data;
3692 }
3693
3694 // ----------------------------------------------------------------------------
3695
3696 void
3697 CdlValuableBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool modifiable, bool minimal)
3698 {
3699     CYG_REPORT_FUNCNAME("CdlValuable::save");
3700     CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
3701     CYG_PRECONDITION_THISC();
3702     CYG_PRECONDITION_CLASSC(interp);
3703
3704     std::string data = "";
3705     std::string indent_string = std::string(indentation, ' ');
3706     std::string tmp_value     = "";
3707     CdlSimpleValue simple_value;
3708
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.
3712     //
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.
3716     if (minimal) {
3717         
3718         if (modifiable) {
3719             if (this->has_source(CdlValueSource_User)) {
3720                 data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3721             }
3722             if (this->has_source(CdlValueSource_Wizard)) {
3723                 data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3724             }
3725             if (this->has_source(CdlValueSource_Inferred)) {
3726                 data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3727             }
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");
3733                 }
3734                 data += indent_string + "value_source " + current_source_string + "\n";
3735             }
3736         }
3737         
3738     } else {
3739     
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";
3749             }
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";
3753             }
3754         }
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) +
3762                     '\n';
3763
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;
3768                 try {
3769                     active_if_value = (*expr_i)->eval(context);
3770                 } catch(CdlEvalException e) {
3771                     active_if_value = false;
3772                 } catch(std::bad_alloc) {
3773                     throw;
3774                 }
3775                 data += indent_string + "#   --> " + (active_if_value ? one : zero) + "\n";
3776             }
3777         }
3778         
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()) {
3782             data += '\n';
3783         }
3784
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";
3794         }
3795          
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";
3802             break;
3803           case CdlValueFlavor_BoolData:
3804             data += indent_string + "# Flavor: booldata\n";
3805             break;
3806           case CdlValueFlavor_Data:
3807             data += indent_string + "# Flavor: data\n";
3808             break;
3809           default:
3810             break;
3811         }
3812             
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.
3815         if (!modifiable) {
3816             switch(this->get_flavor()) {
3817               case CdlValueFlavor_None :
3818                 break;
3819               case CdlValueFlavor_Bool :
3820                 data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + '\n';
3821                 break;
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';
3825                 break;
3826               case CdlValueFlavor_Data :
3827                 data += indent_string + "# Current_value: " +
3828                     CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3829                 break;
3830               default:
3831                 break;
3832             }
3833         
3834         } else if (CdlValueFlavor_None != this->get_flavor()) {
3835
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";
3842             } else {
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";
3846             }
3847         
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";
3855             }
3856
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";
3861             }
3862         
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");
3872             }
3873             if (this->get_source() == expected_source) {
3874                 data += indent_string + "# value_source " + current_source_string + "\n";
3875             } else {
3876                 data += indent_string + "value_source " + current_source_string + "\n";
3877             }
3878
3879             // Always output the default value as a comment.
3880             data += indent_string + "# Default value: ";
3881             
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)
3890                     + "\n";
3891             } else {
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";
3896             }
3897         }
3898
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';
3904         
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);
3909             }
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);
3913             }
3914         }
3915     
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";
3919         }
3920
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";
3929
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;
3934                 try {
3935                     active_if_value = (*expr_i)->eval(context);
3936                 } catch(CdlEvalException e) {
3937                     active_if_value = false;
3938                 } catch(std::bad_alloc) {
3939                     throw;
3940                 }
3941                 data += indent_string + "#   --> " + (active_if_value ? one : zero) + "\n";
3942             }
3943         }
3944
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++) {
3951             
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();
3955             
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)) {
3961                 
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);
3976                     }
3977                     data += '\n';
3978                 }
3979             }
3980         }
3981     }
3982
3983     interp->write_data(chan, data);
3984     
3985     CYG_REPORT_RETURN();
3986 }
3987
3988 int
3989 CdlValuableBody::savefile_value_source_command(CdlInterpreter interp, int argc, const char* argv[])
3990 {
3991     CYG_REPORT_FUNCNAME("CdlValuable::savefile_value_source_command");
3992     CYG_REPORT_FUNCARG2XV(interp, argc);
3993     CYG_PRECONDITION_CLASSC(interp);
3994
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);
3999
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\"";
4006         } else {
4007             msg += "The specified value source is not valid.";
4008         }
4009         CdlParse::report_error(interp, "", msg);
4010     } else {
4011         valuable->set_source(transaction, source);
4012     }
4013     
4014     return TCL_OK;
4015 }
4016
4017 int
4018 CdlValuableBody::savefile_xxx_value_command(CdlInterpreter interp, int argc, const char* argv[], CdlValueSource source)
4019 {
4020     CYG_REPORT_FUNCNAME("CdlValuable::savefile_xxx_value_command");
4021     CYG_REPORT_FUNCARG3XV(interp, argc, source);
4022     CYG_PRECONDITION_CLASSC(interp);
4023
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);
4028
4029     bool error = false;
4030     bool warn  = false;
4031     std::string msg = "";
4032     if (CdlValueFlavor_None == valuable->get_flavor()) {
4033         msg = "Options with flavor \"none\" cannot be modified.";
4034         error = true;
4035     } else if (!valuable->is_modifiable()) {
4036         msg = "This option is not user-modifiable.";
4037         error = true;
4038     } else {
4039         switch(valuable->get_flavor()) {
4040           case CdlValueFlavor_Bool :
4041               if (2 != argc) {
4042                   msg = "Invalid boolean value, expecting 0 or 1";
4043                   error = true;
4044               } else {
4045                   bool x;
4046                   Cdl::string_to_bool(argv[1], x);
4047                   valuable->set_enabled(transact, x, source);
4048               }
4049               break;
4050           case CdlValueFlavor_Data :
4051               if (2 != argc) {
4052                   msg = "Invalid data value, expecting a single string";
4053                   error = true;
4054               } else {
4055                   valuable->set_value(transact, argv[1], source);
4056               }
4057               break;
4058           case CdlValueFlavor_BoolData:
4059               if (3 != argc) {
4060                   msg = "Invalid booldata value, expecting a boolean followed by a string";
4061                   error = true;
4062               } else {
4063                   bool x;
4064                   Cdl::string_to_bool(argv[1], x);
4065                   valuable->set_enabled_and_value(transact, x, argv[2], source);
4066               }
4067               break;
4068           default:
4069             CYG_FAIL("Invalid value flavor detected");
4070             break;
4071         }
4072     }
4073
4074     if (error || warn) {
4075         msg = std::string("Invalid value command for ") + valuable->get_class_name() + " " + valuable->get_name() + "\n"
4076             + msg;
4077         if (error) {
4078             CdlParse::report_error(interp, "", msg);
4079         } else {
4080             CdlParse::report_warning(interp, "", msg);
4081         }
4082     }
4083
4084     return TCL_OK;
4085 }
4086
4087 int
4088 CdlValuableBody::savefile_user_value_command(CdlInterpreter interp, int argc, const char* argv[])
4089 {
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();
4093     return result;
4094 }
4095
4096 int
4097 CdlValuableBody::savefile_wizard_value_command(CdlInterpreter interp, int argc, const char* argv[])
4098 {
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();
4102     return result;
4103 }
4104
4105 int
4106 CdlValuableBody::savefile_inferred_value_command(CdlInterpreter interp, int argc, const char* argv[])
4107 {
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();
4111     return result;
4112 }
4113
4114 //}}}