source: SVN/cambria/redboot/host/libcdl/value.cxx @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 139.9 KB
Line 
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// ----------------------------------------------------------------------------
67CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValue);
68CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListValue);
69CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValuableBody);
70
71//}}}
72//{{{  CdlSimpleValue class             
73
74//{{{  Constructors                     
75
76// ----------------------------------------------------------------------------
77
78CdlSimpleValue::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
92CdlSimpleValue::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
106CdlSimpleValue::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
120CdlSimpleValue::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
134CdlSimpleValue::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
148CdlSimpleValue::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
167CdlSimpleValue::~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
186CdlSimpleValue&
187CdlSimpleValue::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
204CdlSimpleValue&
205CdlSimpleValue::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
220CdlSimpleValue&
221CdlSimpleValue::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
236CdlSimpleValue&
237CdlSimpleValue::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
257CdlSimpleValue&
258CdlSimpleValue::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
280void
281CdlSimpleValue::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
367std::string
368CdlSimpleValue::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
388bool
389CdlSimpleValue::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
417cdl_int
418CdlSimpleValue::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
432bool
433CdlSimpleValue::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
457double
458CdlSimpleValue::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
472bool
473CdlSimpleValue::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
512void
513CdlSimpleValue::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
526void
527CdlSimpleValue::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
542void
543CdlSimpleValue::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
562CdlValueFormat
563CdlSimpleValue::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
573void
574CdlSimpleValue::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
584void
585CdlSimpleValue::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
603void
604CdlSimpleValue::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
619bool
620CdlSimpleValue::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
649bool
650CdlSimpleValue::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
689static 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
698CdlValue::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
730CdlValue::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
755CdlValue& 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
782CdlValue::~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// ----------------------------------------------------------------------------
805bool
806CdlValue::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.
840CdlValueFlavor
841CdlValue::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
861void
862CdlValue::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
957void
958CdlValue::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
971CdlValueSource
972CdlValue::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
983bool
984CdlValue::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
1000void
1001CdlValue::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
1039bool
1040CdlValue::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
1060std::string
1061CdlValue::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
1078bool
1079CdlValue::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
1096bool
1097CdlValue::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
1114cdl_int
1115CdlValue::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
1132double
1133CdlValue::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
1150CdlSimpleValue
1151CdlValue::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
1172void
1173CdlValue::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
1190void
1191CdlValue::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
1208void
1209CdlValue::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
1231void
1232CdlValue::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
1279CdlListValue::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
1293CdlListValue::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
1310CdlListValue & 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
1330CdlListValue::~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
1356const std::vector<CdlSimpleValue>&
1357CdlListValue::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
1367const std::vector<std::pair<cdl_int, cdl_int> >&
1368CdlListValue::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
1378const std::vector<std::pair<double, double> >&
1379CdlListValue::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
1412bool
1413CdlListValue::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
1434bool
1435CdlListValue::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
1466bool
1467CdlListValue::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
1498bool
1499CdlListValue::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
1534bool
1535CdlListValue::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
1555void
1556CdlValuableBody::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
1586int
1587CdlValuableBody::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
1597bool
1598CdlValuableBody::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
1625CdlDialog
1626CdlValuableBody::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
1654void
1655CdlValuableBody::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
1685int
1686CdlValuableBody::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
1695bool
1696CdlValuableBody::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
1722CdlWizard
1723CdlValuableBody::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
1752void
1753CdlValuableBody::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
1780int
1781CdlValuableBody::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
1791bool
1792CdlValuableBody::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
1803CdlProperty_ListExpression
1804CdlValuableBody::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
1827void
1828CdlValuableBody::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
1872int
1873CdlValuableBody::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
1882bool
1883CdlValuableBody::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
1894CdlProperty_Expression
1895CdlValuableBody::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
1918void
1919CdlValuableBody::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?
1964int
1965CdlValuableBody::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
1975bool
1976CdlValuableBody::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
1987CdlProperty_Expression
1988CdlValuableBody::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
2012void
2013CdlValuableBody::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
2044int
2045CdlValuableBody::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
2055bool
2056CdlValuableBody::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
2067void
2068CdlValuableBody::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
2092void
2093CdlValuableBody::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
2120int
2121CdlValuableBody::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
2131bool
2132CdlValuableBody::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
2143void
2144CdlValuableBody::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
2168void
2169CdlValuableBody::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
2233int
2234CdlValuableBody::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
2245void
2246CdlValuableBody::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
2275static void
2276parse_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
2294int
2295CdlValuableBody::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>
2306int
2307CdlValuableBody::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
2320int
2321CdlValuableBody::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
2331bool
2332CdlValuableBody::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
2343cdl_tcl_code
2344CdlValuableBody::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
2365int
2366CdlValuableBody::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
2376bool
2377CdlValuableBody::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}
2387cdl_tcl_code
2388CdlValuableBody::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
2414bool
2415CdlValuableBody::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
2437void
2438CdlValuableBody::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// ----------------------------------------------------------------------------
2670const CdlValue&
2671CdlValuableBody::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
2681CdlValueFlavor
2682CdlValuableBody::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
2693CdlValueSource
2694CdlValuableBody::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
2705bool
2706CdlValuableBody::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
2717bool
2718CdlValuableBody::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
2729std::string
2730CdlValuableBody::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
2741bool
2742CdlValuableBody::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
2753cdl_int
2754CdlValuableBody::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
2765bool
2766CdlValuableBody::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
2777double
2778CdlValuableBody::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
2789CdlSimpleValue
2790CdlValuableBody::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// ----------------------------------------------------------------------------
2802CdlValueSource
2803CdlValuableBody::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
2816bool
2817CdlValuableBody::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
2830bool
2831CdlValuableBody::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
2844std::string
2845CdlValuableBody::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
2858bool
2859CdlValuableBody::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
2872cdl_int
2873CdlValuableBody::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
2886bool
2887CdlValuableBody::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
2900double
2901CdlValuableBody::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
2914CdlSimpleValue
2915CdlValuableBody::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.
2935void
2936CdlValuableBody::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.
2994void
2995CdlValuableBody::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
3015void
3016CdlValuableBody::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.
3057void
3058CdlValuableBody::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
3078bool
3079CdlValuableBody::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
3127void
3128CdlValuableBody::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
3142void
3143CdlValuableBody::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
3157void
3158CdlValuableBody::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
3172void
3173CdlValuableBody::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
3187void
3188CdlValuableBody::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
3202void
3203CdlValuableBody::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
3229void
3230CdlValuableBody::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
3246void
3247CdlValuableBody::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
3262void
3263CdlValuableBody::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
3279void
3280CdlValuableBody::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
3296void
3297CdlValuableBody::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
3314void
3315CdlValuableBody::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
3331void
3332CdlValuableBody::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
3353CdlValuableBody::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
3366CdlValuableBody::~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
3380std::string
3381CdlValuableBody::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// ----------------------------------------------------------------------------
3390bool
3391CdlValuableBody::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
3412void
3413CdlValuableBody::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...
3454void
3455CdlValuableBody::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// ----------------------------------------------------------------------------
3554void
3555CdlValuableBody::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.
3573bool
3574CdlValuableBody::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
3598static std::string one    = "1";     // Needed to avoid confusing the compiler
3599static std::string zero   = "0";
3600
3601static std::string
3602value_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.
3628static CdlValueSource
3629get_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()
3661static std::string
3662follow_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
3696void
3697CdlValuableBody::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
3988int
3989CdlValuableBody::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
4017int
4018CdlValuableBody::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
4087int
4088CdlValuableBody::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
4096int
4097CdlValuableBody::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
4105int
4106CdlValuableBody::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//}}}
Note: See TracBrowser for help on using the repository browser.