OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [cdlcore.hxx] - Diff between revs 26 and 174

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 26 Rev 174
#ifndef __CDLCORE_HXX
#ifndef __CDLCORE_HXX
# define __CDLCORE_HXX
# define __CDLCORE_HXX
//{{{  Banner
//{{{  Banner
//==========================================================================
//==========================================================================
//
//
//      cdlcore.hxx
//      cdlcore.hxx
//
//
//      The core parts of the library. This header defines aspects of
//      The core parts of the library. This header defines aspects of
//      CDL that are shared between software cdl, hcdl, scdl, and any
//      CDL that are shared between software cdl, hcdl, scdl, and any
//      future languages based on the same core technology.
//      future languages based on the same core technology.
//
//
//==========================================================================
//==========================================================================
//####COPYRIGHTBEGIN####
//####COPYRIGHTBEGIN####
//
//
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Copyright (C) 2002 Bart Veer
// Copyright (C) 2002 Bart Veer
// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
//
//
// This file is part of the eCos host tools.
// This file is part of the eCos host tools.
//
//
// This program is free software; you can redistribute it and/or modify it
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
// any later version.
//
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
// more details.
//
//
// You should have received a copy of the GNU General Public License along with
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc.,
// this program; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
//
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
//
//
//####COPYRIGHTEND####
//####COPYRIGHTEND####
//==========================================================================
//==========================================================================
//#####DESCRIPTIONBEGIN####
//#####DESCRIPTIONBEGIN####
//
//
// Author(s):           bartv
// Author(s):           bartv
// Contributors:        bartv
// Contributors:        bartv
// Date:                1999-04-15
// Date:                1999-04-15
//
//
//####DESCRIPTIONEND####
//####DESCRIPTIONEND####
//==========================================================================
//==========================================================================
//}}}
//}}}
//{{{  Platform dependencies
//{{{  Platform dependencies
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Visual C++ has the delightful feature that the source browser will generate
// Visual C++ has the delightful feature that the source browser will generate
// warnings if there are any identifiers of length >= 256 characters, while at
// warnings if there are any identifiers of length >= 256 characters, while at
// the same time use of templates in the standard C++ library can easily
// the same time use of templates in the standard C++ library can easily
// generate functions that long. It appears that the only way to disable the
// generate functions that long. It appears that the only way to disable the
// warnings is by use of a %$#@(%*&%! #pragma.
// warnings is by use of a %$#@(%*&%! #pragma.
//
//
// Similarly, VC++ gives spurious warnings when it comes to multiple virtual
// Similarly, VC++ gives spurious warnings when it comes to multiple virtual
// inheritance.
// inheritance.
#ifdef _MSC_VER
#ifdef _MSC_VER
# pragma warning( disable: 4786 )
# pragma warning( disable: 4786 )
# pragma warning( disable: 4250 )
# pragma warning( disable: 4250 )
#endif
#endif
//}}}
//}}}
//{{{  nested #include's
//{{{  nested #include's
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The libcdl API is defined using parts of the standard C++ library,
// The libcdl API is defined using parts of the standard C++ library,
// including strings and various bits of STL. Therefore these headers must
// including strings and various bits of STL. Therefore these headers must
// be #include'd here for the header file to work.
// be #include'd here for the header file to work.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
//  is needed in various places in the implementation.
//  is needed in various places in the implementation.
// This #include should be moved to an implementation-specific
// This #include should be moved to an implementation-specific
// header.
// header.
#include 
#include 
// Now for some eCos host-side infrastructure headers.
// Now for some eCos host-side infrastructure headers.
//
//
// Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
// Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
#include 
#include 
// Some of the classes need to reference the cyg_assert_class_zeal enum.
// Some of the classes need to reference the cyg_assert_class_zeal enum.
// Also inline functions may perform assertions.
// Also inline functions may perform assertions.
#include 
#include 
// This header file also depends on having a suitable Tcl installation
// This header file also depends on having a suitable Tcl installation
// Unfortunately  does some ugly things in the interests of
// Unfortunately  does some ugly things in the interests of
// portability, including defining symbols such as EXTERN when
// portability, including defining symbols such as EXTERN when
// necessary, and this has to be patched up here as cleanly as possible.
// necessary, and this has to be patched up here as cleanly as possible.
#ifndef CONST
#ifndef CONST
# define __CDL_CONST_UNDEFINED
# define __CDL_CONST_UNDEFINED
#endif
#endif
#ifndef EXTERN
#ifndef EXTERN
# define __CDL_EXTERN_UNDEFINED
# define __CDL_EXTERN_UNDEFINED
#endif
#endif
#ifndef VOID
#ifndef VOID
# define __CDL_VOID_UNDEFINED
# define __CDL_VOID_UNDEFINED
#endif
#endif
#ifndef CHAR
#ifndef CHAR
# define __CDL_CHAR_UNDEFINED
# define __CDL_CHAR_UNDEFINED
#endif
#endif
#ifndef SHORT
#ifndef SHORT
# define __CDL_SHORT_UNDEFINED
# define __CDL_SHORT_UNDEFINED
#endif
#endif
#ifndef LONG
#ifndef LONG
# define __CDL_LONG_UNDEFINED
# define __CDL_LONG_UNDEFINED
#endif
#endif
extern "C" {
extern "C" {
#include 
#include 
}
}
#ifdef __CDL_CONST_UNDEFINED
#ifdef __CDL_CONST_UNDEFINED
# undef CONST
# undef CONST
# undef __CDL_CONST_UNDEFINED
# undef __CDL_CONST_UNDEFINED
#endif
#endif
#ifdef __CDL_EXTERN_UNDEFINED
#ifdef __CDL_EXTERN_UNDEFINED
# undef EXTERN
# undef EXTERN
# undef __CDL_EXTERN_UNDEFINED
# undef __CDL_EXTERN_UNDEFINED
#endif
#endif
#ifdef __CDL_VOID_UNDEFINED
#ifdef __CDL_VOID_UNDEFINED
# undef VOID
# undef VOID
# undef __CDL_VOID_UNDEFINED
# undef __CDL_VOID_UNDEFINED
#endif
#endif
#ifdef __CDL_CHAR_UNDEFINED
#ifdef __CDL_CHAR_UNDEFINED
# undef CHAR
# undef CHAR
# undef __CDL_CHAR_UNDEFINED
# undef __CDL_CHAR_UNDEFINED
#endif
#endif
#ifdef __CDL_SHORT_UNDEFINED
#ifdef __CDL_SHORT_UNDEFINED
# undef SHORT
# undef SHORT
# undef __CDL_SHORT_UNDEFINED
# undef __CDL_SHORT_UNDEFINED
#endif
#endif
#ifdef __CDL_LONG_UNDEFINED
#ifdef __CDL_LONG_UNDEFINED
# undef LONG
# undef LONG
# undef __CDL_LONG_UNDEFINED
# undef __CDL_LONG_UNDEFINED
#endif
#endif
//}}}
//}}}
//{{{  Primitive types, constants:, enums, etc.
//{{{  Primitive types, constants:, enums, etc.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The CDL languages are defined in terms of arbitrary precision
// The CDL languages are defined in terms of arbitrary precision
// arithmetic. This is necessary to allow e.g. pointers to be
// arithmetic. This is necessary to allow e.g. pointers to be
// manipulated at the CDL level on 64 bit target processors.
// manipulated at the CDL level on 64 bit target processors.
//
//
// Temporarily it is not necessary to provide this precision, so it is
// Temporarily it is not necessary to provide this precision, so it is
// convenient to stick to 64 bit integers as provided by the
// convenient to stick to 64 bit integers as provided by the
// underlying infrastructure. However the API is defined in terms of
// underlying infrastructure. However the API is defined in terms of
// the type cdl_int, so that it will be easier in future to make the
// the type cdl_int, so that it will be easier in future to make the
// change to the correct datatype. At that point cdl_int can be
// change to the correct datatype. At that point cdl_int can be
// redefined to be a class which supports the appropriate operators.
// redefined to be a class which supports the appropriate operators.
typedef cyg_int64 cdl_int;
typedef cyg_int64 cdl_int;
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// A common concept in the CDL language is a small amount of TCL code.
// A common concept in the CDL language is a small amount of TCL code.
// This is currently stored as a simple string. Conceivably it could
// This is currently stored as a simple string. Conceivably it could
// be byte-compiled and stored accordingly.
// be byte-compiled and stored accordingly.
typedef std::string  cdl_tcl_code;
typedef std::string  cdl_tcl_code;
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// CDL values.
// CDL values.
//
//
// CDL is a declarative programming language. It does involve the
// CDL is a declarative programming language. It does involve the
// manipulation of values, but such values do not necessarily
// manipulation of values, but such values do not necessarily
// correspond to hardware-level entities such as integers or double
// correspond to hardware-level entities such as integers or double
// precision numbers. Hence the term "type" is avoided, "flavor"
// precision numbers. Hence the term "type" is avoided, "flavor"
// is used instead. CDL understands four different flavors.
// is used instead. CDL understands four different flavors.
//
//
//    None  |  Bool
//    None  |  Bool
//  --------+--------
//  --------+--------
//    Data  |BoolData
//    Data  |BoolData
//
//
//
//
// The flavor "none" is used for entities that serve only as
// The flavor "none" is used for entities that serve only as
// placeholders in the hierarchy, allowing other entities to be
// placeholders in the hierarchy, allowing other entities to be
// grouped more easily.
// grouped more easily.
//
//
// Boolean entities can be either enabled or disabled. This is the
// Boolean entities can be either enabled or disabled. This is the
// most common flavor for software configuration options, the user can
// most common flavor for software configuration options, the user can
// either enable or disable some unit of functionality. For software
// either enable or disable some unit of functionality. For software
// packages implemented in C or C++ the implementation is obvious: iff
// packages implemented in C or C++ the implementation is obvious: iff
// the entity is enabled then there will be a #define, and code will
// the entity is enabled then there will be a #define, and code will
// check the setting using e.g. #ifdef.
// check the setting using e.g. #ifdef.
//
//
// The flavor "data" implies some arbitrary data. Internally this will
// The flavor "data" implies some arbitrary data. Internally this will
// be held as a string. Other properties such as legal_values,
// be held as a string. Other properties such as legal_values,
// check_proc and entry_proc can be used to constrain the
// check_proc and entry_proc can be used to constrain the
// actual values, for example to an integer value within a certain
// actual values, for example to an integer value within a certain
// range.
// range.
//
//
// The flavor "booldata" combines the previous two: it means that
// The flavor "booldata" combines the previous two: it means that
// the option can be either enabled or disabled, and if it is
// the option can be either enabled or disabled, and if it is
// enabled then it must have a value as per legal_values etc.
// enabled then it must have a value as per legal_values etc.
// One example of this is a software package: this may be either
// One example of this is a software package: this may be either
// enabled or disabled, and if it is enabled then it has a value
// enabled or disabled, and if it is enabled then it has a value
// corresponding to the version string. Another example is a hardware
// corresponding to the version string. Another example is a hardware
// pin: this may or may not be connected, and if it is connected
// pin: this may or may not be connected, and if it is connected
// then its value identifies some other pin.
// then its value identifies some other pin.
//
//
// An entity's flavor is not always sufficient by itself to specify
// An entity's flavor is not always sufficient by itself to specify
// how the user can manipulate it in a graphical tool. Obviously an
// how the user can manipulate it in a graphical tool. Obviously an
// entity of flavor "none" cannot be manipulated at all. Flavor "bool"
// entity of flavor "none" cannot be manipulated at all. Flavor "bool"
// normally implies a checkbutton, but occasionally a radiobutton will
// normally implies a checkbutton, but occasionally a radiobutton will
// be more appropriate. "Data" says very little about the user
// be more appropriate. "Data" says very little about the user
// interaction, it will be necessary to examine other properties such
// interaction, it will be necessary to examine other properties such
// as legal_values to determine a sensible representation. The same
// as legal_values to determine a sensible representation. The same
// goes for "BoolData", with the additional possibility that the
// goes for "BoolData", with the additional possibility that the
// entity may be disabled.
// entity may be disabled.
//
//
// It can be argued that three of the flavors are redundant: both Bool
// It can be argued that three of the flavors are redundant: both Bool
// and BoolData could be implemented as cases of "Data" with a special
// and BoolData could be implemented as cases of "Data" with a special
// legal value "disabled" (or false, or whatever); "None" could be
// legal value "disabled" (or false, or whatever); "None" could be
// implemented as constant "Data"; effectively CDL would manipulate
// implemented as constant "Data"; effectively CDL would manipulate
// all data as strings, just like e.g. all variables in Tcl, or just
// all data as strings, just like e.g. all variables in Tcl, or just
// like all scalars in Perl. This approach is certainly tempting and
// like all scalars in Perl. This approach is certainly tempting and
// might well make it easier to document the language, but in practice
// might well make it easier to document the language, but in practice
// it would result in more verbose CDL: boolean entities really are a
// it would result in more verbose CDL: boolean entities really are a
// different beast from data entities.
// different beast from data entities.
//
//
// It can also be argued that there should be more flavors. For
// It can also be argued that there should be more flavors. For
// example there could be separate flavors for integer data, floating
// example there could be separate flavors for integer data, floating
// point data, string data, and so on. There are a number of good
// point data, string data, and so on. There are a number of good
// reasons for not doing so:
// reasons for not doing so:
//
//
// 1) applying separate constraints such as legal_values allows much
// 1) applying separate constraints such as legal_values allows much
//    finer control over the actual values, for example numbers within a
//    finer control over the actual values, for example numbers within a
//    given range. As likely as not, a value will be constrained to
//    given range. As likely as not, a value will be constrained to
//    something smaller than the range MININT to MAXINT (whatever those
//    something smaller than the range MININT to MAXINT (whatever those
//    happen to be for the current target).
//    happen to be for the current target).
//
//
// 2) where do you stop? Do you provide separate flavors for signed
// 2) where do you stop? Do you provide separate flavors for signed
//    vs. unsigned? Char, wchar_t, short, int, long, long long? How about
//    vs. unsigned? Char, wchar_t, short, int, long, long long? How about
//    the eCos data types cyg_ucount8, cyg_uint8, ... Is there support
//    the eCos data types cyg_ucount8, cyg_uint8, ... Is there support
//    for enums? Arrays? Bitfields? Structures? Unions? C++ classes?
//    for enums? Arrays? Bitfields? Structures? Unions? C++ classes?
//    How about other programming languages such as Ada or Java?
//    How about other programming languages such as Ada or Java?
//
//
//    Any attempt to implement a grand union of all data types in CDL
//    Any attempt to implement a grand union of all data types in CDL
//    is doomed to failure and should not be attempted. Treating
//    is doomed to failure and should not be attempted. Treating
//    everything as a string instead has proven successful in a number
//    everything as a string instead has proven successful in a number
//    of languages, including Tcl and Perl.
//    of languages, including Tcl and Perl.
//
//
// 3) for some variants of CDL, for example hardware CDL, it may not
// 3) for some variants of CDL, for example hardware CDL, it may not
//    make much sense to display a value directly and allow it to be
//    make much sense to display a value directly and allow it to be
//    manipulated directly. The value associated with a pin entity
//    manipulated directly. The value associated with a pin entity
//    identifies the pin to which it is connected, and typically
//    identifies the pin to which it is connected, and typically
//    this value will be manipulated by drag and drop rather than by
//    this value will be manipulated by drag and drop rather than by
//    typing some characters. Such a value certainly does not correspond
//    typing some characters. Such a value certainly does not correspond
//    to any machine data type.
//    to any machine data type.
//
//
// Another reason for extending the number of flavors is to provide
// Another reason for extending the number of flavors is to provide
// more information. For example there could be a specialized version
// more information. For example there could be a specialized version
// of the boolean flavor called "radio". This would imply a specific
// of the boolean flavor called "radio". This would imply a specific
// representation in the user interface, and it would also impose
// representation in the user interface, and it would also impose
// a constraint that it implicitly precludes any other radio entities
// a constraint that it implicitly precludes any other radio entities
// within the same group. However the same information can be specified
// within the same group. However the same information can be specified
// by other more general means such as requires statements.
// by other more general means such as requires statements.
enum CdlValueFlavor {
enum CdlValueFlavor {
    CdlValueFlavor_Invalid      =  0,
    CdlValueFlavor_Invalid      =  0,
    CdlValueFlavor_None         =  1,
    CdlValueFlavor_None         =  1,
    CdlValueFlavor_Bool         =  2,
    CdlValueFlavor_Bool         =  2,
    CdlValueFlavor_BoolData     =  3,
    CdlValueFlavor_BoolData     =  3,
    CdlValueFlavor_Data         =  4
    CdlValueFlavor_Data         =  4
};
};
// Another important aspect of a value is where it came from. There
// Another important aspect of a value is where it came from. There
// are a number of possible sources: the default value, calculated
// are a number of possible sources: the default value, calculated
// from a default_value property; a value inferred by the inference
// from a default_value property; a value inferred by the inference
// engine; a value set by a wizard; and a value set explicitly by
// engine; a value set by a wizard; and a value set explicitly by
// the user. These sources have different priorities, so for example
// the user. These sources have different priorities, so for example
// the inference engine can safely replace a calculated default
// the inference engine can safely replace a calculated default
// value without prompting the user, but changing a user-set value
// value without prompting the user, but changing a user-set value
// automatically is undesirable.
// automatically is undesirable.
//
//
// Wizard-generated values are considered more valuable than default
// Wizard-generated values are considered more valuable than default
// or inferred values (there is some user input involved), but less
// or inferred values (there is some user input involved), but less
// valuable than values set explicitly by the user: the idea is that
// valuable than values set explicitly by the user: the idea is that
// a wizard asks fairly generic questions and makes a best guess at
// a wizard asks fairly generic questions and makes a best guess at
// the correct values, which may not be precise enough for the
// the correct values, which may not be precise enough for the
// user's needs.
// user's needs.
//
//
// Arguably dialogs provide a level between wizards and users, in that
// Arguably dialogs provide a level between wizards and users, in that
// a dialog can theoretically manipulate several entities in one go so
// a dialog can theoretically manipulate several entities in one go so
// it is a less precise way of setting values. At this stage it does
// it is a less precise way of setting values. At this stage it does
// not seem worthwhile to add this distinction.
// not seem worthwhile to add this distinction.
//
//
// The library actually maintains separate values for each source,
// The library actually maintains separate values for each source,
// as well as the current source which is what actually gets used.
// as well as the current source which is what actually gets used.
// In theory it is possible for the user interface code to let
// In theory it is possible for the user interface code to let
// the user switch between these. It is not yet clear whether this
// the user switch between these. It is not yet clear whether this
// makes sense from an end user's perspective.
// makes sense from an end user's perspective.
enum CdlValueSource {
enum CdlValueSource {
    CdlValueSource_Invalid              = -1, // 0 is needed for array indexing
    CdlValueSource_Invalid              = -1, // 0 is needed for array indexing
    CdlValueSource_Default              =  0,
    CdlValueSource_Default              =  0,
    CdlValueSource_Inferred             =  1,
    CdlValueSource_Inferred             =  1,
    CdlValueSource_Wizard               =  2,
    CdlValueSource_Wizard               =  2,
    CdlValueSource_User                 =  3,
    CdlValueSource_User                 =  3,
    CdlValueSource_Current              =  4
    CdlValueSource_Current              =  4
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Update support.
// Update support.
//
//
// When there is a change to a node and there are references to that node,
// When there is a change to a node and there are references to that node,
// the referencing properties will want to be informed about this. There
// the referencing properties will want to be informed about this. There
// are various different kinds of changes, not all of which are always
// are various different kinds of changes, not all of which are always
// relevant. For example, if a CDL entity gets destroyed or unloaded then
// relevant. For example, if a CDL entity gets destroyed or unloaded then
// all referencing entities are likely to want to know about this, but
// all referencing entities are likely to want to know about this, but
// if a container's value changes then this has no effect on a reference
// if a container's value changes then this has no effect on a reference
// in e.g. a "parent" property. In some cases it is also useful to apply
// in e.g. a "parent" property. In some cases it is also useful to apply
// updates to nodes rather than properties, e.g. when a node becomes
// updates to nodes rather than properties, e.g. when a node becomes
// active or inactive.
// active or inactive.
//
//
// The generic update code is also used for initialization and finalization,
// The generic update code is also used for initialization and finalization,
// i.e. when the source object itself has just been loaded or is
// i.e. when the source object itself has just been loaded or is
// being unloaded.
// being unloaded.
//
//
// For any particular update at most one bit set, but it is often
// For any particular update at most one bit set, but it is often
// appropriate to treat several different kinds of update with
// appropriate to treat several different kinds of update with
// common code. Hence the enum values can be or'ed and and'ed.
// common code. Hence the enum values can be or'ed and and'ed.
enum CdlUpdate {
enum CdlUpdate {
    CdlUpdate_Loaded            = 0x0001,       // The source has just been loaded
    CdlUpdate_Loaded            = 0x0001,       // The source has just been loaded
    CdlUpdate_Init              = 0x0002,       // Second-phase of a load operation
    CdlUpdate_Init              = 0x0002,       // Second-phase of a load operation
    CdlUpdate_Unloading         = 0x0004,       // The source is being unloaded
    CdlUpdate_Unloading         = 0x0004,       // The source is being unloaded
    CdlUpdate_Created           = 0x0008,       // The destination has just been created
    CdlUpdate_Created           = 0x0008,       // The destination has just been created
    CdlUpdate_Destroyed         = 0x0010,       // The destination is being destroyed
    CdlUpdate_Destroyed         = 0x0010,       // The destination is being destroyed
    CdlUpdate_ValueChange       = 0x0020,       // The destination's value has changed.
    CdlUpdate_ValueChange       = 0x0020,       // The destination's value has changed.
                                                // This gets applied to nodes as well
                                                // This gets applied to nodes as well
    CdlUpdate_ActiveChange      = 0x0040        // The node has become active or inactive
    CdlUpdate_ActiveChange      = 0x0040        // The node has become active or inactive
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Inference engine callback.
// Inference engine callback.
//
//
// During a transaction there may be one or more invocations of the inference
// During a transaction there may be one or more invocations of the inference
// engine, followed by a callback which should display the current transaction
// engine, followed by a callback which should display the current transaction
// status to the user and allow one or more recommended fixes to be accepted.
// status to the user and allow one or more recommended fixes to be accepted.
// The callback's return code indicates what should happen next. "Cancel"
// The callback's return code indicates what should happen next. "Cancel"
// is pretty obvious. "Continue" may result in a commit, or it may result in
// is pretty obvious. "Continue" may result in a commit, or it may result in
// another iteration.
// another iteration.
enum CdlInferenceCallbackResult {
enum CdlInferenceCallbackResult {
    CdlInferenceCallbackResult_Continue = 0x01,
    CdlInferenceCallbackResult_Continue = 0x01,
    CdlInferenceCallbackResult_Cancel   = 0x02
    CdlInferenceCallbackResult_Cancel   = 0x02
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Widget hints.
// Widget hints.
//
//
// The library can provide a hint to the GUI code as to a sensible
// The library can provide a hint to the GUI code as to a sensible
// widget to use for displaying a particular valuable. There are separate
// widget to use for displaying a particular valuable. There are separate
// hints for the bool and data parts.
// hints for the bool and data parts.
enum CdlBoolWidget {
enum CdlBoolWidget {
    CdlBoolWidget_None                  = 0,    // The boolean part is not applicable
    CdlBoolWidget_None                  = 0,    // The boolean part is not applicable
    CdlBoolWidget_CustomDialog          = 1,    // There is a valid custom dialog property
    CdlBoolWidget_CustomDialog          = 1,    // There is a valid custom dialog property
    CdlBoolWidget_CheckButton           = 2,    // For simple booleans
    CdlBoolWidget_CheckButton           = 2,    // For simple booleans
    CdlBoolWidget_Radio                 = 3,    // For several mutual exclusive options,
    CdlBoolWidget_Radio                 = 3,    // For several mutual exclusive options,
                                                // the data structure will provide a string identifier
                                                // the data structure will provide a string identifier
};
};
enum CdlValueWidget {
enum CdlValueWidget {
    CdlValueWidget_None                 = 0,    // The value part is not applicable
    CdlValueWidget_None                 = 0,    // The value part is not applicable
    CdlValueWidget_CustomDialog         = 1,    // There is a valid custom dialog property
    CdlValueWidget_CustomDialog         = 1,    // There is a valid custom dialog property
    CdlValueWidget_Loadable             = 2,    // Use package/version dialog
    CdlValueWidget_Loadable             = 2,    // Use package/version dialog
    CdlValueWidget_EntryBox             = 3,    // Fallback
    CdlValueWidget_EntryBox             = 3,    // Fallback
    CdlValueWidget_MultilineString      = 4,    // For complicated strings
    CdlValueWidget_MultilineString      = 4,    // For complicated strings
    CdlValueWidget_DecimalRange         = 5,    // e.g. 1 to 16
    CdlValueWidget_DecimalRange         = 5,    // e.g. 1 to 16
                                                // Could be implemented as scale, radio buttons, entry, pull-down menu,
                                                // Could be implemented as scale, radio buttons, entry, pull-down menu,
                                                // combo box, ... depending on GUI conventions and number of entries
                                                // combo box, ... depending on GUI conventions and number of entries
    CdlValueWidget_HexRange             = 6,    // e.g. 0x01 to 0x10
    CdlValueWidget_HexRange             = 6,    // e.g. 0x01 to 0x10
    CdlValueWidget_OctalRange           = 7,    // e.g. 01 to 020
    CdlValueWidget_OctalRange           = 7,    // e.g. 01 to 020
    CdlValueWidget_DoubleRange          = 8,    // e.g. 0.1 to 0.2
    CdlValueWidget_DoubleRange          = 8,    // e.g. 0.1 to 0.2
    CdlValueWidget_NumericSet           = 9,    // e.g. 1 2 4 8 16
    CdlValueWidget_NumericSet           = 9,    // e.g. 1 2 4 8 16
                                                // The exact nature of the numbers is irrelevant, they will only
                                                // The exact nature of the numbers is irrelevant, they will only
                                                // get displayed, not edited
                                                // get displayed, not edited
                                                // Could be implemented as radio buttons, entry widget, pull-down menu,
                                                // Could be implemented as radio buttons, entry widget, pull-down menu,
                                                // combo box, ... depending on GUI conventions and number of entries
                                                // combo box, ... depending on GUI conventions and number of entries
                                                // Each entry can have its own representation
                                                // Each entry can have its own representation
    CdlValueWidget_StringSet            = 10    // e.g. "ram", "rom"
    CdlValueWidget_StringSet            = 10    // e.g. "ram", "rom"
    // More to be added, e.g. for compiler flag handling
    // More to be added, e.g. for compiler flag handling
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Value formats.
// Value formats.
//
//
// The CDL input data can accept numbers in a variety of formats,
// The CDL input data can accept numbers in a variety of formats,
// for example hexadecimal as well as decimal. It is desirable to try
// for example hexadecimal as well as decimal. It is desirable to try
// to keep track of this formatting information where possible, so
// to keep track of this formatting information where possible, so
// that what the user sees and what ends up in header files corresponds
// that what the user sees and what ends up in header files corresponds
// more closely to what is in the raw CDL data. For example, it is
// more closely to what is in the raw CDL data. For example, it is
// much easier to understand 0x7fffffff than its decimal equivalent.
// much easier to understand 0x7fffffff than its decimal equivalent.
//
//
// The information kept here is very imprecise, it provides only
// The information kept here is very imprecise, it provides only
// minimal formatting information. It is not clear yet whether this
// minimal formatting information. It is not clear yet whether this
// will suffice or whether something more exact is going to be needed.
// will suffice or whether something more exact is going to be needed.
enum CdlValueFormat
enum CdlValueFormat
{
{
    CdlValueFormat_Default              = 0,
    CdlValueFormat_Default              = 0,
    CdlValueFormat_Hex                  = 1,
    CdlValueFormat_Hex                  = 1,
    CdlValueFormat_Octal                = 2
    CdlValueFormat_Octal                = 2
};
};
//}}}
//}}}
//{{{  Exception classes
//{{{  Exception classes
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Some parts of the library make use of C++ exception handling. A number
// Some parts of the library make use of C++ exception handling. A number
// of exception classes related to this library are useful. In addition
// of exception classes related to this library are useful. In addition
// just about every part of the library can throw std::bad_alloc, but this
// just about every part of the library can throw std::bad_alloc, but this
// is not checked for explicitly anywhere.
// is not checked for explicitly anywhere.
// This class is used for all exceptions where an error message should
// This class is used for all exceptions where an error message should
// be displayed to the user. There is a single string message associated
// be displayed to the user. There is a single string message associated
// with the exception.
// with the exception.
class CdlStringException {
class CdlStringException {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlStringException(std::string message_arg) {
    CdlStringException(std::string message_arg) {
        message = message_arg;
        message = message_arg;
    }
    }
    CdlStringException(const CdlStringException& original) {
    CdlStringException(const CdlStringException& original) {
        message = original.message;
        message = original.message;
    }
    }
    CdlStringException& operator=(const CdlStringException& original) {
    CdlStringException& operator=(const CdlStringException& original) {
        message = original.message;
        message = original.message;
        return *this;
        return *this;
    }
    }
    ~CdlStringException() {
    ~CdlStringException() {
        message = "";
        message = "";
    }
    }
    const std::string& get_message() const {
    const std::string& get_message() const {
        return message;
        return message;
    }
    }
  private:
  private:
    std::string message;
    std::string message;
    CdlStringException();
    CdlStringException();
};
};
// CdlInputOutputException: this gets thrown when something goes wrong during
// CdlInputOutputException: this gets thrown when something goes wrong during
// file I/O operations, e.g. a file exists but cannot be opened. The
// file I/O operations, e.g. a file exists but cannot be opened. The
// exception contains a simple string explaining the error. This string
// exception contains a simple string explaining the error. This string
// may contain multiple lines, it is intended to be written to stderr
// may contain multiple lines, it is intended to be written to stderr
// or displayed in either a text widget or a dialog box.
// or displayed in either a text widget or a dialog box.
//
//
// A separate class rather than a typedef is used to avoid any possible
// A separate class rather than a typedef is used to avoid any possible
// error message confusion. Everything gets inlined so there should be
// error message confusion. Everything gets inlined so there should be
// no performance issues.
// no performance issues.
class CdlInputOutputException : public CdlStringException {
class CdlInputOutputException : public CdlStringException {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlInputOutputException(std::string message_arg) :
    CdlInputOutputException(std::string message_arg) :
        CdlStringException(message_arg) {
        CdlStringException(message_arg) {
    }
    }
    CdlInputOutputException(const CdlInputOutputException& original) :
    CdlInputOutputException(const CdlInputOutputException& original) :
        CdlStringException(original) {
        CdlStringException(original) {
    }
    }
    CdlInputOutputException& operator=(const CdlInputOutputException& original) {
    CdlInputOutputException& operator=(const CdlInputOutputException& original) {
        (void) CdlStringException::operator=(original);
        (void) CdlStringException::operator=(original);
        return *this;
        return *this;
    }
    }
};
};
// This class is used when any parsing happens at the C++ level rather
// This class is used when any parsing happens at the C++ level rather
// than at the Tcl level. The exception should be caught before it
// than at the Tcl level. The exception should be caught before it
// propagates through the Tcl interpreter, or the latter will end up
// propagates through the Tcl interpreter, or the latter will end up
// in an inconsistent state.
// in an inconsistent state.
class CdlParseException : public CdlStringException {
class CdlParseException : public CdlStringException {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlParseException(std::string message_arg) :
    CdlParseException(std::string message_arg) :
        CdlStringException(message_arg) {
        CdlStringException(message_arg) {
    }
    }
    CdlParseException(const CdlParseException& original) :
    CdlParseException(const CdlParseException& original) :
        CdlStringException(original) {
        CdlStringException(original) {
    }
    }
    CdlParseException& operator=(const CdlParseException& original) {
    CdlParseException& operator=(const CdlParseException& original) {
        (void) CdlStringException::operator=(original);
        (void) CdlStringException::operator=(original);
        return *this;
        return *this;
    }
    }
};
};
// Evaluating an expression may fail for a variety of reasons, e.g. because
// Evaluating an expression may fail for a variety of reasons, e.g. because
// some referenced entity has not been loaded into the configuration.
// some referenced entity has not been loaded into the configuration.
// This exception can be thrown in such cases.
// This exception can be thrown in such cases.
class CdlEvalException : public CdlStringException {
class CdlEvalException : public CdlStringException {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlEvalException(std::string message_arg) :
    CdlEvalException(std::string message_arg) :
        CdlStringException(message_arg) {
        CdlStringException(message_arg) {
    }
    }
    CdlEvalException(const CdlEvalException& original) :
    CdlEvalException(const CdlEvalException& original) :
        CdlStringException(original) {
        CdlStringException(original) {
    }
    }
    CdlEvalException& operator=(const CdlEvalException& original) {
    CdlEvalException& operator=(const CdlEvalException& original) {
        (void) CdlStringException::operator=(original);
        (void) CdlStringException::operator=(original);
        return *this;
        return *this;
    }
    }
};
};
//}}}
//}}}
//{{{  Forward declarations of the body classes
//{{{  Forward declarations of the body classes
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This section provides forward declarations of the main classes in
// This section provides forward declarations of the main classes in
// the core of the library. Each variant of CDL will define additional
// the core of the library. Each variant of CDL will define additional
// classes, e.g. cdl_option, but these will usually be derived from
// classes, e.g. cdl_option, but these will usually be derived from
// the core ones.
// the core ones.
// There are three types of expression in CDL:
// There are three types of expression in CDL:
// 1) ordinary expressions evaluate to a single value. The most common
// 1) ordinary expressions evaluate to a single value. The most common
//    use is for the legal_values property.
//    use is for the legal_values property.
// 2) list expressions evaluate to a range of values, e.g. 1 to 10,
// 2) list expressions evaluate to a range of values, e.g. 1 to 10,
//    and the most common use is for the legal_values property.
//    and the most common use is for the legal_values property.
// 3) goal expressions evaluate to either true or false and are used
// 3) goal expressions evaluate to either true or false and are used
//    for e.g. requires and active_if properties.
//    for e.g. requires and active_if properties.
class CdlExpressionBody;
class CdlExpressionBody;
class CdlListExpressionBody;
class CdlListExpressionBody;
class CdlGoalExpressionBody;
class CdlGoalExpressionBody;
// There are also objects for simple values, values and list values.
// There are also objects for simple values, values and list values.
// These are expanded classes, there are no associated pointer
// These are expanded classes, there are no associated pointer
// types. It is quite likely that values need to be copied around
// types. It is quite likely that values need to be copied around
// on the stack.
// on the stack.
class CdlSimpleValue;
class CdlSimpleValue;
class CdlValue;
class CdlValue;
class CdlListValue;
class CdlListValue;
// Properties. The base class is CdlProperty, and there are a number
// Properties. The base class is CdlProperty, and there are a number
// of derived classes provided as standard. Additional derived classes
// of derived classes provided as standard. Additional derived classes
// may be added in future.
// may be added in future.
class CdlPropertyBody;
class CdlPropertyBody;
class CdlProperty_MinimalBody;
class CdlProperty_MinimalBody;
class CdlProperty_StringBody;
class CdlProperty_StringBody;
class CdlProperty_TclCodeBody;
class CdlProperty_TclCodeBody;
class CdlProperty_ReferenceBody;
class CdlProperty_ReferenceBody;
class CdlProperty_StringVectorBody;
class CdlProperty_StringVectorBody;
class CdlProperty_ExpressionBody;
class CdlProperty_ExpressionBody;
class CdlProperty_ListExpressionBody;
class CdlProperty_ListExpressionBody;
class CdlProperty_GoalExpressionBody;
class CdlProperty_GoalExpressionBody;
// Base classes. CDL entities such as options and components derive
// Base classes. CDL entities such as options and components derive
// from one or more of these, using virtual inheritance.
// from one or more of these, using virtual inheritance.
//
//
// The lowest-level class is CdlNodeBody.
// The lowest-level class is CdlNodeBody.
//
//
// 1) a node usually lives in a hierarchy, below a toplevel
// 1) a node usually lives in a hierarchy, below a toplevel
//    and with a container object as the parent. However nodes
//    and with a container object as the parent. However nodes
//    can live outside a container on a temporary basis,
//    can live outside a container on a temporary basis,
//    and toplevel objects have no parent.
//    and toplevel objects have no parent.
//
//
// 2) a node has a name that is unique within the hierarchy.
// 2) a node has a name that is unique within the hierarchy.
//
//
// 3) a node has a vector of properties. Actually some entities
// 3) a node has a vector of properties. Actually some entities
//    will have an empty vector, e.g. the orphans container
//    will have an empty vector, e.g. the orphans container
//    that is internal to the library. However it is too
//    that is internal to the library. However it is too
//    inconvenient to have separate base classes for these.
//    inconvenient to have separate base classes for these.
//
//
// 4) nodes can be referred to by properties in other nodes.
// 4) nodes can be referred to by properties in other nodes.
class CdlNodeBody;
class CdlNodeBody;
// A container is a node that can contain other nodes.
// A container is a node that can contain other nodes.
class CdlContainerBody;
class CdlContainerBody;
// A loadable object is a container whose data has come out of a CDL
// A loadable object is a container whose data has come out of a CDL
// script of some sort. It also stores details about all entities that
// script of some sort. It also stores details about all entities that
// were loaded via this script (even if some of them were reparented)
// were loaded via this script (even if some of them were reparented)
// thus supporting unload operations.
// thus supporting unload operations.
class CdlLoadableBody;
class CdlLoadableBody;
// A toplevel object is a container that acts as the toplevel of
// A toplevel object is a container that acts as the toplevel of
// a hierarchy, in other words its parent is always 0. In addition
// a hierarchy, in other words its parent is always 0. In addition
// a toplevel keeps track of all the names used in the hierarchy,
// a toplevel keeps track of all the names used in the hierarchy,
// thus facilitating navigation.
// thus facilitating navigation.
class CdlToplevelBody;
class CdlToplevelBody;
// The remaining classes all add functionality to CdlNode, directly or
// The remaining classes all add functionality to CdlNode, directly or
// indirectly.
// indirectly.
//
//
// A user-visible object is likely to appear in the user interface.
// A user-visible object is likely to appear in the user interface.
// This means it may have an alias string, a description, a
// This means it may have an alias string, a description, a
// documentation URL, and a gui_hint field.
// documentation URL, and a gui_hint field.
class CdlUserVisibleBody;
class CdlUserVisibleBody;
// A valuable object has a value that can be retrieved but not
// A valuable object has a value that can be retrieved but not
// necessarily modified by the user. For example the value of an
// necessarily modified by the user. For example the value of an
// interface is always calculated and users can never change it.
// interface is always calculated and users can never change it.
// Valuable objects have a whole bunch of associated properties
// Valuable objects have a whole bunch of associated properties
// including dependencies.
// including dependencies.
class CdlValuableBody;
class CdlValuableBody;
// A parentable object has the parent property, i.e. it can
// A parentable object has the parent property, i.e. it can
// be reparented to anywhere in the hierarchy
// be reparented to anywhere in the hierarchy
class CdlParentableBody;
class CdlParentableBody;
// A buildable object is a valuable object that may result in
// A buildable object is a valuable object that may result in
// something being built, typically a library in the case of
// something being built, typically a library in the case of
// software packages.
// software packages.
class CdlBuildableBody;
class CdlBuildableBody;
// A loadable that contains buildables
// A loadable that contains buildables
class CdlBuildLoadableBody;
class CdlBuildLoadableBody;
// A definable object is a valuable object whose value can result
// A definable object is a valuable object whose value can result
// in #define statements in a header file
// in #define statements in a header file
class CdlDefinableBody;
class CdlDefinableBody;
// A loadable which can contain definables
// A loadable which can contain definables
class CdlDefineLoadableBody;
class CdlDefineLoadableBody;
// TODO: add instantiation support
// TODO: add instantiation support
// Custom dialogs and wizards are provided by the core.
// Custom dialogs and wizards are provided by the core.
class CdlDialogBody;
class CdlDialogBody;
class CdlWizardBody;
class CdlWizardBody;
class CdlInterfaceBody;
class CdlInterfaceBody;
// Support for Tcl interpreters is also in the core, since it is
// Support for Tcl interpreters is also in the core, since it is
// difficult to do anything CDL-related without at least one Tcl
// difficult to do anything CDL-related without at least one Tcl
// interpreter lying around.
// interpreter lying around.
class CdlInterpreterBody;
class CdlInterpreterBody;
// The basic conflict class is part of the core library, as are a
// The basic conflict class is part of the core library, as are a
// number of common derived classes for specific types of conflict.
// number of common derived classes for specific types of conflict.
class CdlConflictBody;
class CdlConflictBody;
class CdlConflict_UnresolvedBody;
class CdlConflict_UnresolvedBody;
class CdlConflict_IllegalValueBody;
class CdlConflict_IllegalValueBody;
class CdlConflict_EvalExceptionBody;
class CdlConflict_EvalExceptionBody;
class CdlConflict_RequiresBody;
class CdlConflict_RequiresBody;
class CdlConflict_DataBody;
class CdlConflict_DataBody;
// Many operations happen (or may happen) in the context of a
// Many operations happen (or may happen) in the context of a
// transaction. This is necessary to keep track of the various
// transaction. This is necessary to keep track of the various
// changes that can happen: for example, changing a component's
// changes that can happen: for example, changing a component's
// value may require other entities' default values to be
// value may require other entities' default values to be
// recalculated; it may change some legal_values list expressions,
// recalculated; it may change some legal_values list expressions,
// causing current values to become invalid; it may affect
// causing current values to become invalid; it may affect
// "requires" properties, causing goals to become satisfied or
// "requires" properties, causing goals to become satisfied or
// not-satisfied; it may change the "active" state of everything
// not-satisfied; it may change the "active" state of everything
// below the component, not to mention any entity with an
// below the component, not to mention any entity with an
// "active_if" properties, and when an entity becomes active or
// "active_if" properties, and when an entity becomes active or
// inactive that may in turn affect other entities.
// inactive that may in turn affect other entities.
//
//
// Keeping track of all of this via recursion is possible, but there
// Keeping track of all of this via recursion is possible, but there
// are problems. If an entity is updated multiple times, no
// are problems. If an entity is updated multiple times, no
// optimizations are possible. It becomes much more difficult to
// optimizations are possible. It becomes much more difficult to
// detect cycles. During an unload operation things can get very
// detect cycles. During an unload operation things can get very
// messy. There is no easy way to track all of the changes and report
// messy. There is no easy way to track all of the changes and report
// them to higher level code via a callback. There is no support
// them to higher level code via a callback. There is no support
// for any kind of rollback. A transaction model potentially
// for any kind of rollback. A transaction model potentially
// provides support for all of this, at the cost of a more
// provides support for all of this, at the cost of a more
// complex API.
// complex API.
class CdlTransactionBody;
class CdlTransactionBody;
// This class is used to pass information back to the application
// This class is used to pass information back to the application
// about what has actually changed in a transaction.
// about what has actually changed in a transaction.
class CdlTransactionCallback;
class CdlTransactionCallback;
// Build info class. This is always an expanded object, but is
// Build info class. This is always an expanded object, but is
// needed here to break a circular dependency.
// needed here to break a circular dependency.
class CdlBuildInfo;
class CdlBuildInfo;
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Typedefs for the pointers. There are separate typedefs to cope with
// Typedefs for the pointers. There are separate typedefs to cope with
// const vs. non-const objects. Otherwise you end up with the problem
// const vs. non-const objects. Otherwise you end up with the problem
// that "const CdlNode x" means that the pointer is const, not the
// that "const CdlNode x" means that the pointer is const, not the
// object pointed at.
// object pointed at.
typedef CdlExpressionBody*              CdlExpression;
typedef CdlExpressionBody*              CdlExpression;
typedef CdlListExpressionBody*          CdlListExpression;
typedef CdlListExpressionBody*          CdlListExpression;
typedef CdlGoalExpressionBody*          CdlGoalExpression;
typedef CdlGoalExpressionBody*          CdlGoalExpression;
typedef CdlPropertyBody*                CdlProperty;
typedef CdlPropertyBody*                CdlProperty;
typedef CdlProperty_MinimalBody*        CdlProperty_Minimal;
typedef CdlProperty_MinimalBody*        CdlProperty_Minimal;
typedef CdlProperty_StringBody*         CdlProperty_String;
typedef CdlProperty_StringBody*         CdlProperty_String;
typedef CdlProperty_TclCodeBody*        CdlProperty_TclCode;
typedef CdlProperty_TclCodeBody*        CdlProperty_TclCode;
typedef CdlProperty_ReferenceBody*      CdlProperty_Reference;
typedef CdlProperty_ReferenceBody*      CdlProperty_Reference;
typedef CdlProperty_StringVectorBody*   CdlProperty_StringVector;
typedef CdlProperty_StringVectorBody*   CdlProperty_StringVector;
typedef CdlProperty_ExpressionBody*     CdlProperty_Expression;
typedef CdlProperty_ExpressionBody*     CdlProperty_Expression;
typedef CdlProperty_ListExpressionBody* CdlProperty_ListExpression;
typedef CdlProperty_ListExpressionBody* CdlProperty_ListExpression;
typedef CdlProperty_GoalExpressionBody* CdlProperty_GoalExpression;
typedef CdlProperty_GoalExpressionBody* CdlProperty_GoalExpression;
typedef CdlNodeBody*                    CdlNode;
typedef CdlNodeBody*                    CdlNode;
typedef CdlContainerBody*               CdlContainer;
typedef CdlContainerBody*               CdlContainer;
typedef CdlLoadableBody*                CdlLoadable;
typedef CdlLoadableBody*                CdlLoadable;
typedef CdlToplevelBody*                CdlToplevel;
typedef CdlToplevelBody*                CdlToplevel;
typedef CdlUserVisibleBody*             CdlUserVisible;
typedef CdlUserVisibleBody*             CdlUserVisible;
typedef CdlValuableBody*                CdlValuable;
typedef CdlValuableBody*                CdlValuable;
typedef CdlParentableBody*              CdlParentable;
typedef CdlParentableBody*              CdlParentable;
typedef CdlBuildableBody*               CdlBuildable;
typedef CdlBuildableBody*               CdlBuildable;
typedef CdlBuildLoadableBody*           CdlBuildLoadable;
typedef CdlBuildLoadableBody*           CdlBuildLoadable;
typedef CdlDefinableBody*               CdlDefinable;
typedef CdlDefinableBody*               CdlDefinable;
typedef CdlDefineLoadableBody*          CdlDefineLoadable;
typedef CdlDefineLoadableBody*          CdlDefineLoadable;
typedef CdlDialogBody*                  CdlDialog;
typedef CdlDialogBody*                  CdlDialog;
typedef CdlWizardBody*                  CdlWizard;
typedef CdlWizardBody*                  CdlWizard;
typedef CdlInterfaceBody*               CdlInterface;
typedef CdlInterfaceBody*               CdlInterface;
typedef CdlInterpreterBody*             CdlInterpreter;
typedef CdlInterpreterBody*             CdlInterpreter;
typedef CdlConflictBody*                CdlConflict;
typedef CdlConflictBody*                CdlConflict;
typedef CdlConflict_UnresolvedBody*     CdlConflict_Unresolved;
typedef CdlConflict_UnresolvedBody*     CdlConflict_Unresolved;
typedef CdlConflict_IllegalValueBody*   CdlConflict_IllegalValue;
typedef CdlConflict_IllegalValueBody*   CdlConflict_IllegalValue;
typedef CdlConflict_EvalExceptionBody*  CdlConflict_EvalException;
typedef CdlConflict_EvalExceptionBody*  CdlConflict_EvalException;
typedef CdlConflict_RequiresBody*       CdlConflict_Requires;
typedef CdlConflict_RequiresBody*       CdlConflict_Requires;
typedef CdlConflict_DataBody*           CdlConflict_Data;
typedef CdlConflict_DataBody*           CdlConflict_Data;
typedef CdlTransactionBody*             CdlTransaction;
typedef CdlTransactionBody*             CdlTransaction;
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
typedef const CdlExpressionBody*              CdlConstExpression;
typedef const CdlExpressionBody*              CdlConstExpression;
typedef const CdlListExpressionBody*          CdlConstListExpression;
typedef const CdlListExpressionBody*          CdlConstListExpression;
typedef const CdlGoalExpressionBody*          CdlConstGoalExpression;
typedef const CdlGoalExpressionBody*          CdlConstGoalExpression;
typedef const CdlPropertyBody*                CdlConstProperty;
typedef const CdlPropertyBody*                CdlConstProperty;
typedef const CdlProperty_MinimalBody*        CdlConstProperty_Minimal;
typedef const CdlProperty_MinimalBody*        CdlConstProperty_Minimal;
typedef const CdlProperty_StringBody*         CdlConstProperty_String;
typedef const CdlProperty_StringBody*         CdlConstProperty_String;
typedef const CdlProperty_TclCodeBody*        CdlConstProperty_TclCode;
typedef const CdlProperty_TclCodeBody*        CdlConstProperty_TclCode;
typedef const CdlProperty_ReferenceBody*      CdlConstProperty_Reference;
typedef const CdlProperty_ReferenceBody*      CdlConstProperty_Reference;
typedef const CdlProperty_StringVectorBody*   CdlConstProperty_StringVector;
typedef const CdlProperty_StringVectorBody*   CdlConstProperty_StringVector;
typedef const CdlProperty_ExpressionBody*     CdlConstProperty_Expression;
typedef const CdlProperty_ExpressionBody*     CdlConstProperty_Expression;
typedef const CdlProperty_ListExpressionBody* CdlConstProperty_ListExpression;
typedef const CdlProperty_ListExpressionBody* CdlConstProperty_ListExpression;
typedef const CdlProperty_GoalExpressionBody* CdlConstProperty_GoalExpression;
typedef const CdlProperty_GoalExpressionBody* CdlConstProperty_GoalExpression;
typedef const CdlNodeBody*                    CdlConstNode;
typedef const CdlNodeBody*                    CdlConstNode;
typedef const CdlContainerBody*               CdlConstContainer;
typedef const CdlContainerBody*               CdlConstContainer;
typedef const CdlLoadableBody*                CdlConstLoadable;
typedef const CdlLoadableBody*                CdlConstLoadable;
typedef const CdlToplevelBody*                CdlConstToplevel;
typedef const CdlToplevelBody*                CdlConstToplevel;
typedef const CdlUserVisibleBody*             CdlConstUserVisible;
typedef const CdlUserVisibleBody*             CdlConstUserVisible;
typedef const CdlValuableBody*                CdlConstValuable;
typedef const CdlValuableBody*                CdlConstValuable;
typedef const CdlParentableBody*              CdlConstParentable;
typedef const CdlParentableBody*              CdlConstParentable;
typedef const CdlBuildableBody*               CdlConstBuildable;
typedef const CdlBuildableBody*               CdlConstBuildable;
typedef const CdlBuildLoadableBody*           CdlConstBuildLoadable;
typedef const CdlBuildLoadableBody*           CdlConstBuildLoadable;
typedef const CdlDefinableBody*               CdlConstDefinable;
typedef const CdlDefinableBody*               CdlConstDefinable;
typedef const CdlDefineLoadableBody*          CdlConstDefineLoadable;
typedef const CdlDefineLoadableBody*          CdlConstDefineLoadable;
typedef const CdlDialogBody*                  CdlConstDialog;
typedef const CdlDialogBody*                  CdlConstDialog;
typedef const CdlWizardBody*                  CdlConstWizard;
typedef const CdlWizardBody*                  CdlConstWizard;
typedef const CdlInterfaceBody*               CdlConstInterface;
typedef const CdlInterfaceBody*               CdlConstInterface;
typedef const CdlInterpreterBody*             CdlConstInterpreter;
typedef const CdlInterpreterBody*             CdlConstInterpreter;
typedef const CdlConflictBody*                CdlConstConflict;
typedef const CdlConflictBody*                CdlConstConflict;
typedef const CdlConflict_UnresolvedBody*     CdlConstConflict_Unresolved;
typedef const CdlConflict_UnresolvedBody*     CdlConstConflict_Unresolved;
typedef const CdlConflict_IllegalValueBody*   CdlConstConflict_IllegalValue;
typedef const CdlConflict_IllegalValueBody*   CdlConstConflict_IllegalValue;
typedef const CdlConflict_EvalExceptionBody*  CdlConstConflict_EvalException;
typedef const CdlConflict_EvalExceptionBody*  CdlConstConflict_EvalException;
typedef const CdlConflict_RequiresBody*       CdlConstConflict_Requires;
typedef const CdlConflict_RequiresBody*       CdlConstConflict_Requires;
typedef const CdlConflict_DataBody*           CdlConstConflict_Data;
typedef const CdlConflict_DataBody*           CdlConstConflict_Data;
typedef const CdlTransactionBody*             CdlConstTransaction;
typedef const CdlTransactionBody*             CdlConstTransaction;
//}}}
//}}}
//{{{  Miscellaneous types etc.
//{{{  Miscellaneous types etc.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This section is used for data types, function prototypes, etc. which could
// This section is used for data types, function prototypes, etc. which could
// not be defined until after the main CDL classes and handles.
// not be defined until after the main CDL classes and handles.
// This typedef is used for error and warning reporting functions.
// This typedef is used for error and warning reporting functions.
// Typically such a function pointer will be passed when the library
// Typically such a function pointer will be passed when the library
// is asked to perform any non-trivial parsing operation, e.g. loading
// is asked to perform any non-trivial parsing operation, e.g. loading
// a package.
// a package.
//
//
// If the error is fatal then this callback function should raise
// If the error is fatal then this callback function should raise
// a CdlParseException.
// a CdlParseException.
typedef void (*CdlDiagnosticFnPtr)(std::string);
typedef void (*CdlDiagnosticFnPtr)(std::string);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This function is used for update handler. Whenever there is a change
// This function is used for update handler. Whenever there is a change
// to CDL entity (it has just been loaded, or its value has changed, or
// to CDL entity (it has just been loaded, or its value has changed, or
// whatever) this can affect other CDL entities that reference it.
// whatever) this can affect other CDL entities that reference it.
// All such references occur via properties, and there should be
// All such references occur via properties, and there should be
// update handlers associated with those properties.
// update handlers associated with those properties.
//
//
// Update handlers are also invoked for initialization and finalization
// Update handlers are also invoked for initialization and finalization
// operations, i.e. when the source object itself has just been loaded
// operations, i.e. when the source object itself has just been loaded
// or is in the process of being unloaded.
// or is in the process of being unloaded.
//
//
// The arguments to an update handler are:
// The arguments to an update handler are:
// 1) the transaction in which the operation takes place
// 1) the transaction in which the operation takes place
// 2) the source object containing the reference
// 2) the source object containing the reference
// 3) the source property containing the reference
// 3) the source property containing the reference
// 4) the destination object. This may be 0 for some update
// 4) the destination object. This may be 0 for some update
//    operations.
//    operations.
// 5) an indication of the change that has happened. This should
// 5) an indication of the change that has happened. This should
//    be a CdlUpdate value.
//    be a CdlUpdate value.
typedef void (*CdlUpdateHandler)(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
typedef void (*CdlUpdateHandler)(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This function is also used for transactions. Typically during a
// This function is also used for transactions. Typically during a
// transaction there will be one or more invocations of the inference engine,
// transaction there will be one or more invocations of the inference engine,
// with callbacks in between to allow one or more of the recommended
// with callbacks in between to allow one or more of the recommended
// changes to be undone.
// changes to be undone.
typedef CdlInferenceCallbackResult (*CdlInferenceCallback)(CdlTransaction);
typedef CdlInferenceCallbackResult (*CdlInferenceCallback)(CdlTransaction);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The TCL API and C++ do not always mesh cleanly, for example a lot
// The TCL API and C++ do not always mesh cleanly, for example a lot
// happens in terms of ClientData which is a void* pointer. To avoid
// happens in terms of ClientData which is a void* pointer. To avoid
// too many casts all over the place libcdl provides a CdlInterpreter
// too many casts all over the place libcdl provides a CdlInterpreter
// class and the following alternative to Tcl_CmdProc*. A single
// class and the following alternative to Tcl_CmdProc*. A single
// function will be used for the TCL command: its ClientData will be
// function will be used for the TCL command: its ClientData will be
// the CdlInterpreterCommand, and the CdlInterpreter is accessible via
// the CdlInterpreterCommand, and the CdlInterpreter is accessible via
// AssocData. This does result in some overheads, but none of these
// AssocData. This does result in some overheads, but none of these
// should be in performance-critical code.
// should be in performance-critical code.
typedef int (*CdlInterpreterCommand)(CdlInterpreter, int, const char*[]);
typedef int (*CdlInterpreterCommand)(CdlInterpreter, int, const char*[]);
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// In the libcdl world it is often convenient to swap whole sets of
// In the libcdl world it is often convenient to swap whole sets of
// commands in and out. For example when executing the body of a
// commands in and out. For example when executing the body of a
// cdl_component it is desirable to swap in commands for all the
// cdl_component it is desirable to swap in commands for all the
// properties that make sense in a component and swap out all the
// properties that make sense in a component and swap out all the
// commands that made sense in a higher level. It is assumed that none
// commands that made sense in a higher level. It is assumed that none
// of the commands being swapped in or out are built-ins. Achieving
// of the commands being swapped in or out are built-ins. Achieving
// this involves a vector of this simple utility structure.
// this involves a vector of this simple utility structure.
class CdlInterpreterCommandEntry {
class CdlInterpreterCommandEntry {
  public:
  public:
    std::string                 name;
    std::string                 name;
    CdlInterpreterCommand       command;
    CdlInterpreterCommand       command;
    CdlInterpreterCommandEntry() : name(""), command(0) {}
    CdlInterpreterCommandEntry() : name(""), command(0) {}
    CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
    CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
        : name(name_arg), command(command_arg)
        : name(name_arg), command(command_arg)
    {
    {
    }
    }
    CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
    CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
        : name(name_arg), command(command_arg)
        : name(name_arg), command(command_arg)
    {
    {
    }
    }
    ~CdlInterpreterCommandEntry()
    ~CdlInterpreterCommandEntry()
    {
    {
        name = "";
        name = "";
        command = 0;
        command = 0;
    }
    }
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Persistence support.
// Persistence support.
// Some applications want to be able to store additional information
// Some applications want to be able to store additional information
// in savefiles, and essentially this involves extra commands that
// in savefiles, and essentially this involves extra commands that
// get executed when the savefile is executed. It is possible that
// get executed when the savefile is executed. It is possible that
// the application reading back the savefile does not understand
// the application reading back the savefile does not understand
// the same set of commands as the application that wrote back the
// the same set of commands as the application that wrote back the
// data, so the library tries hard not to lose data.
// data, so the library tries hard not to lose data.
//
//
// The CdlSaveCallback function typedef is used when installing
// The CdlSaveCallback function typedef is used when installing
// an application-specific savefile command. The first argument
// an application-specific savefile command. The first argument
// indicates the node for which the callback is being invoked:
// indicates the node for which the callback is being invoked:
// this may be the entire toplevel, or just an option, or whatever.
// this may be the entire toplevel, or just an option, or whatever.
//
//
// The CdlSavefileCommand structure keeps track of the command,
// The CdlSavefileCommand structure keeps track of the command,
// the save callback if any (non-zero only for application-specific
// the save callback if any (non-zero only for application-specific
// data, zero implies that the command is handled by the lirary).
// data, zero implies that the command is handled by the lirary).
// The load command is invoked when reading in a savefile and the
// The load command is invoked when reading in a savefile and the
// appropriate command is executed: unrecognised commands will be
// appropriate command is executed: unrecognised commands will be
// processed by CdlToplevelBody::savefile_handle_unknown().
// processed by CdlToplevelBody::savefile_handle_unknown().
typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
struct CdlSavefileCommand {
struct CdlSavefileCommand {
    std::string           name;
    std::string           name;
    CdlSaveCallback       save_callback;
    CdlSaveCallback       save_callback;
    CdlInterpreterCommand load_command;
    CdlInterpreterCommand load_command;
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Widget hint.
// Widget hint.
// This structure provides widget hint information for a CdlValuable.
// This structure provides widget hint information for a CdlValuable.
// There are separate hints for the bool and data parts, and possibly
// There are separate hints for the bool and data parts, and possibly
// some additional data such as a string identifying the set of
// some additional data such as a string identifying the set of
// items in a radio button.
// items in a radio button.
struct CdlWidgetHint {
struct CdlWidgetHint {
    CdlBoolWidget       bool_widget;
    CdlBoolWidget       bool_widget;
    CdlValueWidget      value_widget;
    CdlValueWidget      value_widget;
    std::string         radio_button_interface;
    std::string         radio_button_interface;
};
};
//}}}
//}}}
//{{{  Memory leak detection
//{{{  Memory leak detection
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Provide some macros that are useful for detecting memory leaks. Basically
// Provide some macros that are useful for detecting memory leaks. Basically
// there is a static counter for every class, which gets incremented by the
// there is a static counter for every class, which gets incremented by the
// constructor(s) and decremented by the destructor. Memory leak detection
// constructor(s) and decremented by the destructor. Memory leak detection
// is currently enabled if tracing is enabled. It would be possible to use
// is currently enabled if tracing is enabled. It would be possible to use
// another configure-time option, but the overheads of tracing are likely
// another configure-time option, but the overheads of tracing are likely
// to dwarf the overheads of memory leak detection.
// to dwarf the overheads of memory leak detection.
//
//
// For now the memleak counters are always present, even in non-debug
// For now the memleak counters are always present, even in non-debug
// versions. The overhead is sufficiently small that it can be
// versions. The overhead is sufficiently small that it can be
// ignored.There is control over whether or not the counters get
// ignored.There is control over whether or not the counters get
// updated in the constructor or destructor. Otherwise there would be problems
// updated in the constructor or destructor. Otherwise there would be problems
// with whether or not there should be a semicolon at the end of the
// with whether or not there should be a semicolon at the end of the
// CYGDBG_DECLARE_MEMLEAK_COUNTER() macro definition.
// CYGDBG_DECLARE_MEMLEAK_COUNTER() macro definition.
#define CYGDBG_DECLARE_MEMLEAK_COUNTER()        static int memleak_counter
#define CYGDBG_DECLARE_MEMLEAK_COUNTER()        static int memleak_counter
#define CYGDBG_DEFINE_MEMLEAK_COUNTER(class)    int class::memleak_counter = 0
#define CYGDBG_DEFINE_MEMLEAK_COUNTER(class)    int class::memleak_counter = 0
#define CYGDBG_GET_MEMLEAK_COUNTER(class)       class::memleak_counter
#define CYGDBG_GET_MEMLEAK_COUNTER(class)       class::memleak_counter
#ifdef CYGDBG_USE_TRACING
#ifdef CYGDBG_USE_TRACING
#define CYGDBG_MEMLEAK_CONSTRUCTOR()            this->memleak_counter++;
#define CYGDBG_MEMLEAK_CONSTRUCTOR()            this->memleak_counter++;
#define CYGDBG_MEMLEAK_DESTRUCTOR()             this->memleak_counter--;
#define CYGDBG_MEMLEAK_DESTRUCTOR()             this->memleak_counter--;
#define CYGDBG_MEMLEAK_CHECKTHIS()              if (this->memleak_counter < 0) { return false; }
#define CYGDBG_MEMLEAK_CHECKTHIS()              if (this->memleak_counter < 0) { return false; }
#else
#else
#define CYGDBG_MEMLEAK_CONSTRUCTOR()
#define CYGDBG_MEMLEAK_CONSTRUCTOR()
#define CYGDBG_MEMLEAK_DESTRUCTOR()
#define CYGDBG_MEMLEAK_DESTRUCTOR()
#define CYGDBG_MEMLEAK_CHECKTHIS()
#define CYGDBG_MEMLEAK_CHECKTHIS()
#endif
#endif
//}}}
//}}}
//{{{  Cdl class
//{{{  Cdl class
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// The sole purpose of this class is to provide some utility functions with
// The sole purpose of this class is to provide some utility functions with
// reasonable namespace protection, without requiring that the compiler
// reasonable namespace protection, without requiring that the compiler
// implements namespaces.
// implements namespaces.
class Cdl {
class Cdl {
  public:
  public:
    static bool         is_valid_value_flavor(CdlValueFlavor);
    static bool         is_valid_value_flavor(CdlValueFlavor);
    static bool         is_valid_value_source(CdlValueSource);
    static bool         is_valid_value_source(CdlValueSource);
    static bool         is_valid_cdl_name(const std::string&);
    static bool         is_valid_cdl_name(const std::string&);
    static bool         is_valid_c_preprocessor_symbol(const std::string&);
    static bool         is_valid_c_preprocessor_symbol(const std::string&);
    static bool         string_to_integer(std::string, cdl_int&);
    static bool         string_to_integer(std::string, cdl_int&);
    static bool         string_to_double(std::string, double&);
    static bool         string_to_double(std::string, double&);
    static bool         string_to_bool(std::string, bool&);
    static bool         string_to_bool(std::string, bool&);
    static void         integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default);
    static void         integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default);
    static std::string  integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default);
    static std::string  integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default);
    static void         double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default);
    static void         double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default);
    static std::string  double_to_string(double, CdlValueFormat = CdlValueFormat_Default);
    static std::string  double_to_string(double, CdlValueFormat = CdlValueFormat_Default);
    static void         bool_to_string(bool, std::string&);
    static void         bool_to_string(bool, std::string&);
    static std::string  bool_to_string(bool);
    static std::string  bool_to_string(bool);
    static void         integer_to_double(cdl_int, double&);
    static void         integer_to_double(cdl_int, double&);
    static double       integer_to_double(cdl_int);
    static double       integer_to_double(cdl_int);
    static bool         double_to_integer(double, cdl_int&);
    static bool         double_to_integer(double, cdl_int&);
    static bool         string_to_flavor(std::string, CdlValueFlavor&);
    static bool         string_to_flavor(std::string, CdlValueFlavor&);
    static bool         flavor_to_string(CdlValueFlavor, std::string&);
    static bool         flavor_to_string(CdlValueFlavor, std::string&);
    static bool         string_to_source(std::string, CdlValueSource&);
    static bool         string_to_source(std::string, CdlValueSource&);
    static bool         source_to_string(CdlValueSource, std::string&);
    static bool         source_to_string(CdlValueSource, std::string&);
    static std::string  get_library_version();
    static std::string  get_library_version();
    static void         set_interactive(bool = true);
    static void         set_interactive(bool = true);
    static bool         is_interactive();
    static bool         is_interactive();
    static bool         truth() { return true; }
    static bool         truth() { return true; }
    static bool         falsehood() { return false; }
    static bool         falsehood() { return false; }
    // return values are -1,0,1 just like strcmp(). The most recent
    // return values are -1,0,1 just like strcmp(). The most recent
    // version is the smallest.
    // version is the smallest.
    static int          compare_versions(std::string, std::string);
    static int          compare_versions(std::string, std::string);
    // Also provide an STL-friendly comparison class
    // Also provide an STL-friendly comparison class
    class version_cmp {
    class version_cmp {
      public:
      public:
        bool operator()(const std::string& v1, const std::string& v2) const {
        bool operator()(const std::string& v1, const std::string& v2) const {
            return Cdl::compare_versions(v1,v2) < 0;
            return Cdl::compare_versions(v1,v2) < 0;
        }
        }
    };
    };
    // Split a version string into major, minor and release numbers.
    // Split a version string into major, minor and release numbers.
    static void         split_version_string(const std::string&, std::string& /* major */,
    static void         split_version_string(const std::string&, std::string& /* major */,
                                             std::string& /* minor */, std::string& /* release */);
                                             std::string& /* minor */, std::string& /* release */);
    // It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL
    // It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL
    // and turn it into a short form, i.e. kernel.
    // and turn it into a short form, i.e. kernel.
    static std::string  get_short_form(const std::string&);
    static std::string  get_short_form(const std::string&);
  private:
  private:
    static bool         interactive;
    static bool         interactive;
};
};
//}}}
//}}}
//{{{  CdlInterpreter class
//{{{  CdlInterpreter class
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// libcdl requires access to a Tcl interpreter. For now the standard
// libcdl requires access to a Tcl interpreter. For now the standard
// interpreter is used. In the long run it may be better to use a
// interpreter is used. In the long run it may be better to use a
// custom parser in places, if only to improve the diagnostics messages
// custom parser in places, if only to improve the diagnostics messages
// that users see.
// that users see.
//
//
// Consider the case of software CDL (other CDL variants will have
// Consider the case of software CDL (other CDL variants will have
// similar requirements). A Tcl interpreter is needed to read in the
// similar requirements). A Tcl interpreter is needed to read in the
// data for a given package. It will also be needed at various stages
// data for a given package. It will also be needed at various stages
// when the data is being manipulated, e.g. to display a custom dialog
// when the data is being manipulated, e.g. to display a custom dialog
// or to execute e.g. a check_proc or a define_proc. Each package
// or to execute e.g. a check_proc or a define_proc. Each package
// should run in its own safe interpreter with limited capabilities:
// should run in its own safe interpreter with limited capabilities:
// file I/O is limited to read-only, but read-write in the build and
// file I/O is limited to read-only, but read-write in the build and
// install trees; network I/O is out of the question, at least until
// install trees; network I/O is out of the question, at least until
// appropriate security support is added to the CDL language itself.
// appropriate security support is added to the CDL language itself.
// However the interpreter should be extended with additional commands
// However the interpreter should be extended with additional commands
// like cdl_get and cdl_set to access the configuration data.
// like cdl_get and cdl_set to access the configuration data.
//
//
// For security and robustness reasons it is desirable to have
// For security and robustness reasons it is desirable to have
// separate interpreters for the various packages. This leads to the
// separate interpreters for the various packages. This leads to the
// concept of a master interpreter for the entire configuration, and a
// concept of a master interpreter for the entire configuration, and a
// group of slave interpreters, one per package. In this model it
// group of slave interpreters, one per package. In this model it
// is convenient to have the configuration and package entities
// is convenient to have the configuration and package entities
// associated directly with the interpreter. Note that a single
// associated directly with the interpreter. Note that a single
// application may have several configurations loaded in memory,
// application may have several configurations loaded in memory,
// so there may be several master interpreters.
// so there may be several master interpreters.
//
//
// Some applications will want to support the graphical side of CDL,
// Some applications will want to support the graphical side of CDL,
// i.e. custom dialogs and wizards. This means linking in Tk, not to
// i.e. custom dialogs and wizards. This means linking in Tk, not to
// mention X11 (or the Windows equivalents), and making some/all of
// mention X11 (or the Windows equivalents), and making some/all of
// the Tk commands available to the safe interpreter. Arguably
// the Tk commands available to the safe interpreter. Arguably
// commands like toplevel should always be disabled. Not all clients
// commands like toplevel should always be disabled. Not all clients
// of libcdl will want the overheads of linking with Tk and X, so this
// of libcdl will want the overheads of linking with Tk and X, so this
// has to be made optional.
// has to be made optional.
//
//
// The approach taken is as follows:
// The approach taken is as follows:
//
//
// 1) there is a class CdlInterpreter which provides access to Tcl
// 1) there is a class CdlInterpreter which provides access to Tcl
//    interpreters. Amongst other things it takes care of converting
//    interpreters. Amongst other things it takes care of converting
//    between C and C++ strings.
//    between C and C++ strings.
//
//
// 2) every toplevel needs its own CdlInterpreter. The application
// 2) every toplevel needs its own CdlInterpreter. The application
//    code should supply this interpreter itself when the toplevel
//    code should supply this interpreter itself when the toplevel
//    is instantiated, allowing it to decide whether or not Tk should
//    is instantiated, allowing it to decide whether or not Tk should
//    be available.
//    be available.
//
//
// 3) each loadable gets its own safe slave interpreter, derived from
// 3) each loadable gets its own safe slave interpreter, derived from
//    the toplevel's interpreter.
//    the toplevel's interpreter.
//    NOTE: initially the slave interpreters are not actually safe. It
//    NOTE: initially the slave interpreters are not actually safe. It
//    is not clear in the long term to what extent per-loadable
//    is not clear in the long term to what extent per-loadable
//    interpreters need to be sandboxes, there are issues such as
//    interpreters need to be sandboxes, there are issues such as
//    doing the equivalent of autoconf tests.
//    doing the equivalent of autoconf tests.
// Tcl 8.4 involved various incompatible API changes related to
// Tcl 8.4 involved various incompatible API changes related to
// const vs. non-const data. #define'ing USE_NON_CONST or
// const vs. non-const data. #define'ing USE_NON_CONST or
// USE_COMPAT_CONST avoids some of the problems, but does not
// USE_COMPAT_CONST avoids some of the problems, but does not
// help much for C++.
// help much for C++.
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
# define CDL_TCL_CONST_CAST(type,var) (var)
# define CDL_TCL_CONST_CAST(type,var) (var)
#else
#else
# define CDL_TCL_CONST_CAST(type,var) const_cast(var)
# define CDL_TCL_CONST_CAST(type,var) const_cast(var)
#endif
#endif
class CdlInterpreterBody
class CdlInterpreterBody
{
{
    friend class        CdlTest;
    friend class        CdlTest;
  public:
  public:
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    // This is how a top-level (i.e. per-toplevel) interpreter
    // This is how a top-level (i.e. per-toplevel) interpreter
    // should get created.
    // should get created.
    static CdlInterpreter       make(Tcl_Interp* = 0);
    static CdlInterpreter       make(Tcl_Interp* = 0);
    // Create a slave interpreter for reading in the data in e.g. a
    // Create a slave interpreter for reading in the data in e.g. a
    // cdl_package
    // cdl_package
    CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
    CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
    // Make the interpreter safe, a one-way operation.
    // Make the interpreter safe, a one-way operation.
    void                make_safe();
    void                make_safe();
    // The destructor is public.
    // The destructor is public.
    virtual ~CdlInterpreterBody();
    virtual ~CdlInterpreterBody();
    // Add or remove commands from an interpreter. This provides
    // Add or remove commands from an interpreter. This provides
    // a more C++-friendly implementation of Tcl's
    // a more C++-friendly implementation of Tcl's
    // CreateCommand() and DeleteCommand().
    // CreateCommand() and DeleteCommand().
    void add_command(std::string, CdlInterpreterCommand);
    void add_command(std::string, CdlInterpreterCommand);
    void remove_command(std::string);
    void remove_command(std::string);
    // In the libcdl world it is also convenient to swap whole sets of
    // In the libcdl world it is also convenient to swap whole sets of
    // commands in and out. This is achieved by push and pop operations.
    // commands in and out. This is achieved by push and pop operations.
    // push returns the old set (0 at the toplevel). pop restores
    // push returns the old set (0 at the toplevel). pop restores
    // the old set.
    // the old set.
    std::vector* push_commands(std::vector&);
    std::vector* push_commands(std::vector&);
    void pop_commands(std::vector*);
    void pop_commands(std::vector*);
    std::vector* get_pushed_commands() const;
    std::vector* get_pushed_commands() const;
    // Similarly, allow variables to be set, unset and queried
    // Similarly, allow variables to be set, unset and queried
    void        set_variable(std::string, std::string);
    void        set_variable(std::string, std::string);
    void        unset_variable(std::string);
    void        unset_variable(std::string);
    std::string get_variable(std::string);
    std::string get_variable(std::string);
    // FIXME: add support for variable traces. These are needed
    // FIXME: add support for variable traces. These are needed
    // for cdl_value and similar utilities.
    // for cdl_value and similar utilities.
    // Provide hooks into the AssocData() facilities associated with
    // Provide hooks into the AssocData() facilities associated with
    // Tcl interpreters. This makes it possible to store arbitrary
    // Tcl interpreters. This makes it possible to store arbitrary
    // data with an interpreter, e.g. to keep track of current state.
    // data with an interpreter, e.g. to keep track of current state.
    void       set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0);
    void       set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0);
    void       delete_assoc_data(const char*);
    void       delete_assoc_data(const char*);
    ClientData get_assoc_data(const char*);
    ClientData get_assoc_data(const char*);
    // Evaluate a string as Tcl code. The return value comes from Tcl, e.g.
    // Evaluate a string as Tcl code. The return value comes from Tcl, e.g.
    // TCL_OK or TCL_ERROR. There are variants depending on whether or not
    // TCL_OK or TCL_ERROR. There are variants depending on whether or not
    // the result string is of interest.
    // the result string is of interest.
    int eval(std::string);
    int eval(std::string);
    int eval(std::string, std::string&);
    int eval(std::string, std::string&);
    // Ditto for any Tcl code that comes from CDL files
    // Ditto for any Tcl code that comes from CDL files
    int eval_cdl_code(const cdl_tcl_code);
    int eval_cdl_code(const cdl_tcl_code);
    int eval_cdl_code(const cdl_tcl_code, std::string&);
    int eval_cdl_code(const cdl_tcl_code, std::string&);
    // And support for evaluating an entire file
    // And support for evaluating an entire file
    int eval_file(std::string);
    int eval_file(std::string);
    int eval_file(std::string, std::string&);
    int eval_file(std::string, std::string&);
    // For use by commands implemented in C++, a way of setting the result
    // For use by commands implemented in C++, a way of setting the result
    void set_result(std::string);
    void set_result(std::string);
    // And a utility to get the result as well.
    // And a utility to get the result as well.
    std::string get_result();
    std::string get_result();
    // Was the result set by the Tcl interpreter or by libcdl?
    // Was the result set by the Tcl interpreter or by libcdl?
    bool result_set_by_cdl();
    bool result_set_by_cdl();
    // A utility to quote data that is going to end up in a TCL script.
    // A utility to quote data that is going to end up in a TCL script.
    static std::string quote(std::string);
    static std::string quote(std::string);
    // Turn some multiline data into a comment.
    // Turn some multiline data into a comment.
    static std::string multiline_comment(const std::string&, int, int = 0);
    static std::string multiline_comment(const std::string&, int, int = 0);
    // Add some data to a comment, allowing for newlines if necessary
    // Add some data to a comment, allowing for newlines if necessary
    static std::string extend_comment(const std::string&, int, int = 0);
    static std::string extend_comment(const std::string&, int, int = 0);
    // Write some data to a savefile, throwing an exception on error
    // Write some data to a savefile, throwing an exception on error
    void write_data(Tcl_Channel, std::string);
    void write_data(Tcl_Channel, std::string);
    // File-related utilities.
    // File-related utilities.
    void locate_subdirs(std::string, std::vector&);
    void locate_subdirs(std::string, std::vector&);
    void locate_all_subdirs(std::string, std::vector&);
    void locate_all_subdirs(std::string, std::vector&);
    void locate_files(std::string, std::vector&);
    void locate_files(std::string, std::vector&);
    void locate_all_files(std::string, std::vector&);
    void locate_all_files(std::string, std::vector&);
    bool is_directory(std::string);
    bool is_directory(std::string);
    bool is_file(std::string);
    bool is_file(std::string);
    // When parsing a CDL script it is convenient to keep track of
    // When parsing a CDL script it is convenient to keep track of
    // a number of items:
    // a number of items:
    //
    //
    // 1) the toplevel, e.g. the entire configuration
    // 1) the toplevel, e.g. the entire configuration
    // 2) the loadable, e.g. the current package
    // 2) the loadable, e.g. the current package
    // 3) the parent of whatever is being processed at the moment
    // 3) the parent of whatever is being processed at the moment
    // 4) the entity, i.e. the thingamajig that is being processed.
    // 4) the entity, i.e. the thingamajig that is being processed.
    // 5) the current file
    // 5) the current file
    // 6) an error reporting function
    // 6) an error reporting function
    //
    //
    // This gives the various commands embedded in the Tcl interpreter
    // This gives the various commands embedded in the Tcl interpreter
    // enough information to do their job. Additional information can
    // enough information to do their job. Additional information can
    // be provided via assoc_data()
    // be provided via assoc_data()
    //
    //
    // There should be only one call to set_toplevel(), for the
    // There should be only one call to set_toplevel(), for the
    // master interpreter. All slaves inherit this, and the toplevel
    // master interpreter. All slaves inherit this, and the toplevel
    // cannot be changed again.
    // cannot be changed again.
    //
    //
    // The loadable field is filled in via make_slave()
    // The loadable field is filled in via make_slave()
    //
    //
    // For some members push and pop functions are more appropriate
    // For some members push and pop functions are more appropriate
    // than set.
    // than set.
    CdlToplevel         get_toplevel() const;
    CdlToplevel         get_toplevel() const;
    CdlLoadable         get_loadable() const;
    CdlLoadable         get_loadable() const;
    CdlContainer        get_container() const;
    CdlContainer        get_container() const;
    CdlNode             get_node() const;
    CdlNode             get_node() const;
    std::string         get_context() const;
    std::string         get_context() const;
    CdlDiagnosticFnPtr  get_error_fn_ptr() const;
    CdlDiagnosticFnPtr  get_error_fn_ptr() const;
    CdlDiagnosticFnPtr  get_warning_fn_ptr() const;
    CdlDiagnosticFnPtr  get_warning_fn_ptr() const;
    CdlTransaction      get_transaction() const;
    CdlTransaction      get_transaction() const;
    void                set_toplevel(CdlToplevel);
    void                set_toplevel(CdlToplevel);
    void                set_transaction(CdlTransaction);
    void                set_transaction(CdlTransaction);
    CdlContainer        push_container(CdlContainer);
    CdlContainer        push_container(CdlContainer);
    void                pop_container(CdlContainer);
    void                pop_container(CdlContainer);
    CdlNode             push_node(CdlNode);
    CdlNode             push_node(CdlNode);
    void                pop_node(CdlNode);
    void                pop_node(CdlNode);
    std::string         push_context(std::string);
    std::string         push_context(std::string);
    void                pop_context(std::string);
    void                pop_context(std::string);
    CdlDiagnosticFnPtr  push_error_fn_ptr(CdlDiagnosticFnPtr);
    CdlDiagnosticFnPtr  push_error_fn_ptr(CdlDiagnosticFnPtr);
    void                pop_error_fn_ptr(CdlDiagnosticFnPtr);
    void                pop_error_fn_ptr(CdlDiagnosticFnPtr);
    CdlDiagnosticFnPtr  push_warning_fn_ptr(CdlDiagnosticFnPtr);
    CdlDiagnosticFnPtr  push_warning_fn_ptr(CdlDiagnosticFnPtr);
    void                pop_warning_fn_ptr(CdlDiagnosticFnPtr);
    void                pop_warning_fn_ptr(CdlDiagnosticFnPtr);
    // Provide utility classes for common push/pop combinations. The
    // Provide utility classes for common push/pop combinations. The
    // push happens during the constructor, the pop during the
    // push happens during the constructor, the pop during the
    // destructor. This can simplify some code, especially when
    // destructor. This can simplify some code, especially when
    // exceptions may get thrown.
    // exceptions may get thrown.
    class DiagSupport {
    class DiagSupport {
      public:
      public:
        DiagSupport(CdlInterpreter interp_arg, CdlDiagnosticFnPtr error_fn_arg, CdlDiagnosticFnPtr warn_fn_arg) {
        DiagSupport(CdlInterpreter interp_arg, CdlDiagnosticFnPtr error_fn_arg, CdlDiagnosticFnPtr warn_fn_arg) {
            interp         = interp_arg;
            interp         = interp_arg;
            saved_error_fn = interp->push_error_fn_ptr(error_fn_arg);
            saved_error_fn = interp->push_error_fn_ptr(error_fn_arg);
            saved_warn_fn  = interp->push_warning_fn_ptr(warn_fn_arg);
            saved_warn_fn  = interp->push_warning_fn_ptr(warn_fn_arg);
        }
        }
        ~DiagSupport() {
        ~DiagSupport() {
            interp->pop_error_fn_ptr(saved_error_fn);
            interp->pop_error_fn_ptr(saved_error_fn);
            interp->pop_warning_fn_ptr(saved_warn_fn);
            interp->pop_warning_fn_ptr(saved_warn_fn);
        }
        }
    private:
    private:
        DiagSupport();
        DiagSupport();
        CdlInterpreter     interp;
        CdlInterpreter     interp;
        CdlDiagnosticFnPtr saved_error_fn;
        CdlDiagnosticFnPtr saved_error_fn;
        CdlDiagnosticFnPtr saved_warn_fn;
        CdlDiagnosticFnPtr saved_warn_fn;
    };
    };
    class ContextSupport {
    class ContextSupport {
      public:
      public:
        ContextSupport(CdlInterpreter interp_arg, std::string context) {
        ContextSupport(CdlInterpreter interp_arg, std::string context) {
            interp = interp_arg;
            interp = interp_arg;
            saved_context = interp->push_context(context);
            saved_context = interp->push_context(context);
        }
        }
        ~ContextSupport() {
        ~ContextSupport() {
            interp->pop_context(saved_context);
            interp->pop_context(saved_context);
        }
        }
      private:
      private:
        ContextSupport();
        ContextSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        std::string    saved_context;
        std::string    saved_context;
    };
    };
    class ContainerSupport {
    class ContainerSupport {
      public:
      public:
        ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
        ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
            interp = interp_arg;
            interp = interp_arg;
            saved_container = interp->push_container(container);
            saved_container = interp->push_container(container);
        }
        }
        ~ContainerSupport() {
        ~ContainerSupport() {
            interp->pop_container(saved_container);
            interp->pop_container(saved_container);
        }
        }
      private:
      private:
        ContainerSupport();
        ContainerSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        CdlContainer   saved_container;
        CdlContainer   saved_container;
    };
    };
    class NodeSupport {
    class NodeSupport {
      public:
      public:
        NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
        NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
            interp = interp_arg;
            interp = interp_arg;
            saved_node = interp->push_node(node);
            saved_node = interp->push_node(node);
        }
        }
        ~NodeSupport() {
        ~NodeSupport() {
            interp->pop_node(saved_node);
            interp->pop_node(saved_node);
        }
        }
      private:
      private:
        NodeSupport();
        NodeSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        CdlNode        saved_node;
        CdlNode        saved_node;
    };
    };
    class CommandSupport {
    class CommandSupport {
      public:
      public:
        CommandSupport(CdlInterpreter interp_arg, std::vector& commands) {
        CommandSupport(CdlInterpreter interp_arg, std::vector& commands) {
            interp = interp_arg;
            interp = interp_arg;
            saved_commands = interp->push_commands(commands);
            saved_commands = interp->push_commands(commands);
        }
        }
        CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
        CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
            unsigned int i;
            unsigned int i;
            for (i = 0; 0 != commands[i].command; i++) {
            for (i = 0; 0 != commands[i].command; i++) {
                new_commands.push_back(commands[i]);
                new_commands.push_back(commands[i]);
            }
            }
            interp = interp_arg;
            interp = interp_arg;
            saved_commands = interp->push_commands(new_commands);
            saved_commands = interp->push_commands(new_commands);
        }
        }
        ~CommandSupport() {
        ~CommandSupport() {
            interp->pop_commands(saved_commands);
            interp->pop_commands(saved_commands);
        }
        }
      private:
      private:
        CommandSupport();
        CommandSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        std::vector* saved_commands;
        std::vector* saved_commands;
        std::vector new_commands;
        std::vector new_commands;
    };
    };
    // Similar utility classes for variables and assoc data.
    // Similar utility classes for variables and assoc data.
    class VariableSupport {
    class VariableSupport {
      public:
      public:
        VariableSupport(CdlInterpreter interp_arg, std::string varname_arg, std::string data) {
        VariableSupport(CdlInterpreter interp_arg, std::string varname_arg, std::string data) {
            interp  = interp_arg;
            interp  = interp_arg;
            varname = varname_arg;
            varname = varname_arg;
            interp->set_variable(varname, data);
            interp->set_variable(varname, data);
        }
        }
        ~VariableSupport() {
        ~VariableSupport() {
            interp->unset_variable(varname);
            interp->unset_variable(varname);
        }
        }
      private:
      private:
        VariableSupport();
        VariableSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        std::string    varname;
        std::string    varname;
    };
    };
    class AssocSupport {
    class AssocSupport {
      public:
      public:
        AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
        AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
            interp = interp_arg;
            interp = interp_arg;
            name   = name_arg;
            name   = name_arg;
            interp->set_assoc_data(name, data, del_proc);
            interp->set_assoc_data(name, data, del_proc);
        }
        }
        ~AssocSupport() {
        ~AssocSupport() {
            interp->delete_assoc_data(name);
            interp->delete_assoc_data(name);
        }
        }
      private:
      private:
        AssocSupport();
        AssocSupport();
        CdlInterpreter interp;
        CdlInterpreter interp;
        const char*    name;
        const char*    name;
    };
    };
    // Some command implementations may want to access other Tcl library
    // Some command implementations may want to access other Tcl library
    // routines such as Tcl_SplitList(). This requires convenient access
    // routines such as Tcl_SplitList(). This requires convenient access
    // to the underlying Tcl interpreter.
    // to the underlying Tcl interpreter.
    Tcl_Interp*         get_tcl_interpreter() const;
    Tcl_Interp*         get_tcl_interpreter() const;
    // For use by the assertion macros.
    // For use by the assertion macros.
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
  private:
  private:
    // This is the Tcl command proc that gets registered for all
    // This is the Tcl command proc that gets registered for all
    // CdlInterpreterCommand instances.
    // CdlInterpreterCommand instances.
    static int          tcl_command_proc(ClientData, Tcl_Interp*, int, const char*[]);
    static int          tcl_command_proc(ClientData, Tcl_Interp*, int, const char*[]);
    // This key is used to access the CdlInterpreter assoc data.
    // This key is used to access the CdlInterpreter assoc data.
    static char*        cdlinterpreter_assoc_data_key;
    static char*        cdlinterpreter_assoc_data_key;
    // Do not allow static instances of a Cdl interpreter. There are too
    // Do not allow static instances of a Cdl interpreter. There are too
    // many possible failure conditions. Cdl interpreters can only be
    // many possible failure conditions. Cdl interpreters can only be
    // created dynamically via make(), which will invoke this.
    // created dynamically via make(), which will invoke this.
    CdlInterpreterBody(Tcl_Interp*);
    CdlInterpreterBody(Tcl_Interp*);
    // Default constructor, copy constructor and assignment are illegal
    // Default constructor, copy constructor and assignment are illegal
    CdlInterpreterBody();
    CdlInterpreterBody();
    CdlInterpreterBody(const CdlInterpreterBody&);
    CdlInterpreterBody(const CdlInterpreterBody&);
    CdlInterpreterBody& operator=(const CdlInterpreterBody&);
    CdlInterpreterBody& operator=(const CdlInterpreterBody&);
    Tcl_Interp*                 tcl_interp;     // The underlying Tcl interpreter
    Tcl_Interp*                 tcl_interp;     // The underlying Tcl interpreter
    bool                        owns_interp;    // Was the Tcl interpreter created by the library?
    bool                        owns_interp;    // Was the Tcl interpreter created by the library?
    std::vector slaves;         // All slave interpreters
    std::vector slaves;         // All slave interpreters
    CdlInterpreter              parent;         // Or else the parent
    CdlInterpreter              parent;         // Or else the parent
    CdlToplevel                 toplevel;       // Data that gets used during the parsing process
    CdlToplevel                 toplevel;       // Data that gets used during the parsing process
    CdlTransaction              transaction;
    CdlTransaction              transaction;
    CdlLoadable                 loadable;
    CdlLoadable                 loadable;
    CdlContainer                container;
    CdlContainer                container;
    CdlNode                     node;
    CdlNode                     node;
    std::string                 context;
    std::string                 context;
    CdlDiagnosticFnPtr          error_fn_ptr;
    CdlDiagnosticFnPtr          error_fn_ptr;
    CdlDiagnosticFnPtr          warning_fn_ptr;
    CdlDiagnosticFnPtr          warning_fn_ptr;
    bool                        cdl_result;
    bool                        cdl_result;
    std::vector* current_commands; // for push() and pop()
    std::vector* current_commands; // for push() and pop()
    enum {
    enum {
        CdlInterpreterBody_Invalid = 0,
        CdlInterpreterBody_Invalid = 0,
        CdlInterpreterBody_Magic   = 0x0be67689
        CdlInterpreterBody_Magic   = 0x0be67689
    } cdlinterpreterbody_cookie;
    } cdlinterpreterbody_cookie;
};
};
//}}}
//}}}
//{{{  CdlReference/Referrer classes
//{{{  CdlReference/Referrer classes
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// CDL objects are organised primarily in a tree hierarchy. For
// CDL objects are organised primarily in a tree hierarchy. For
// example a package contains components, components contain options,
// example a package contains components, components contain options,
// and so on. The tree hierarchy tends to change rather infrequently,
// and so on. The tree hierarchy tends to change rather infrequently,
// so it makes sense to have a quick way of navigating between
// so it makes sense to have a quick way of navigating between
// entities without continuously having to do hash-table lookups. In
// entities without continuously having to do hash-table lookups. In
// addition it is very desirable to make the connectivity
// addition it is very desirable to make the connectivity
// bidirectional: if a "requires" property in option A references
// bidirectional: if a "requires" property in option A references
// option B then it would be useful to have a link back to A from B;
// option B then it would be useful to have a link back to A from B;
// that way, if the value of B changes it is a lot easier to keep
// that way, if the value of B changes it is a lot easier to keep
// things up to date.
// things up to date.
//
//
// Terminology: the entity which contains the reference, e.g. a
// Terminology: the entity which contains the reference, e.g. a
// "requires" property, is the source. The relevant property is the
// "requires" property, is the source. The relevant property is the
// "source property". The entity pointed at is the destination.
// "source property". The entity pointed at is the destination.
//
//
// Unfortunately there may be connections between CDL entities outside
// Unfortunately there may be connections between CDL entities outside
// the tree hierarchy. In particular any property can contain one or
// the tree hierarchy. In particular any property can contain one or
// more references to packages, components, options, wizards, or
// more references to packages, components, options, wizards, or
// whatever. Often these references will be to options etc. within the
// whatever. Often these references will be to options etc. within the
// same package, but some references will go to other packages. There
// same package, but some references will go to other packages. There
// may even be references to other configurations: for example a board
// may even be references to other configurations: for example a board
// may contain both an ordinary processor and a DSP; these two need
// may contain both an ordinary processor and a DSP; these two need
// their own configurations; however a package running on the DSP may
// their own configurations; however a package running on the DSP may
// need to interact with a package running on the processor, and vice
// need to interact with a package running on the processor, and vice
// versa.
// versa.
//
//
// Also, a reference may occur inside an object that is not in the
// Also, a reference may occur inside an object that is not in the
// hierarchy. For example CDL expressions may get evaluated inside Tcl
// hierarchy. For example CDL expressions may get evaluated inside Tcl
// code rather than as part of a property. Such expressions may still
// code rather than as part of a property. Such expressions may still
// contain references to entities in the current configuration.
// contain references to entities in the current configuration.
//
//
// References may not be resolved. When reading in a CDL script there
// References may not be resolved. When reading in a CDL script there
// may be forward references. A reference may involve another package
// may be forward references. A reference may involve another package
// that has not yet been loaded, which is a conflict.
// that has not yet been loaded, which is a conflict.
//
//
// Using simple pointers to store these connections is a bad idea. It
// Using simple pointers to store these connections is a bad idea. It
// makes it a lot harder to figure out what is connected to what, and
// makes it a lot harder to figure out what is connected to what, and
// it introduces horrible consistency problems when packages get
// it introduces horrible consistency problems when packages get
// loaded and unloaded. Instead libCDL provides a CdlReference class.
// loaded and unloaded. Instead libCDL provides a CdlReference class.
// Whenever a CdlProperty contains a reference to some other CDL
// Whenever a CdlProperty contains a reference to some other CDL
// entity there should be a CdlReference object corresponding to this.
// entity there should be a CdlReference object corresponding to this.
// The reverse direction is handled via a CdlReferrer object.
// The reverse direction is handled via a CdlReferrer object.
//
//
// A CdlReference object can be either bound or unbound. By default it
// A CdlReference object can be either bound or unbound. By default it
// is unbound, containing only a string. It can then be bound via a
// is unbound, containing only a string. It can then be bound via a
// member function, examined, and unbound again as required. Creating
// member function, examined, and unbound again as required. Creating
// a binding automatically creates a CdlReferrer entry in the target
// a binding automatically creates a CdlReferrer entry in the target
// object, thus avoiding any risk of inconsistencies.
// object, thus avoiding any risk of inconsistencies.
//
//
// The CdlReference class should not be used outside the hierarchy,
// The CdlReference class should not be used outside the hierarchy,
// since every bound reference must have a referrer object pointing
// since every bound reference must have a referrer object pointing
// back, and this link back can only be valid within the hierarchy.
// back, and this link back can only be valid within the hierarchy.
// Temporary CdlReference objects are useful during the construction
// Temporary CdlReference objects are useful during the construction
// of properties.
// of properties.
//
//
// It is possible that a given property (e.g. a complicated "requires"
// It is possible that a given property (e.g. a complicated "requires"
// expression) has multiple references to another entity. Each of
// expression) has multiple references to another entity. Each of
// these involves a separate CdlReference/CdlReferrer pair.
// these involves a separate CdlReference/CdlReferrer pair.
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The actual CdlReference class.
// The actual CdlReference class.
class CdlReference {
class CdlReference {
    friend class        CdlTest;
    friend class        CdlTest;
    // CdlReferrer must be a friend so that when a package gets unloaded
    // CdlReferrer must be a friend so that when a package gets unloaded
    // it can clean up all references to it.
    // it can clean up all references to it.
    friend class        CdlReferrer;
    friend class        CdlReferrer;
  public:
  public:
    // The default constructor should not normally be used, instead
    // The default constructor should not normally be used, instead
    // a string should be supplied. However there are vectors of
    // a string should be supplied. However there are vectors of
    // reference objects...
    // reference objects...
    CdlReference();
    CdlReference();
    // The main constructor supplies the name of the referenced
    // The main constructor supplies the name of the referenced
    // entity. The resulting object will be unbound.
    // entity. The resulting object will be unbound.
    CdlReference(const std::string);
    CdlReference(const std::string);
    // The copy constructor is legal for unbound objects only.
    // The copy constructor is legal for unbound objects only.
    CdlReference(const CdlReference&);
    CdlReference(const CdlReference&);
    // The assignment operator is needed for STL operations.
    // The assignment operator is needed for STL operations.
    // Again it only makes sense of unbound objects.
    // Again it only makes sense of unbound objects.
    CdlReference& operator=(const CdlReference&);
    CdlReference& operator=(const CdlReference&);
    // The destructor is only valid for unbound objects. All references
    // The destructor is only valid for unbound objects. All references
    // should be unbound before an entity can be destroyed.
    // should be unbound before an entity can be destroyed.
    ~CdlReference();
    ~CdlReference();
    // Access the various fields.
    // Access the various fields.
    void               set_destination_name(const std::string);
    void               set_destination_name(const std::string);
    const std::string& get_destination_name() const;
    const std::string& get_destination_name() const;
    CdlNode            get_destination() const;
    CdlNode            get_destination() const;
    // Binding a reference. Obviously this can only be used when the
    // Binding a reference. Obviously this can only be used when the
    // reference is still unbound. When doing the binding it is
    // reference is still unbound. When doing the binding it is
    // necessary to know:
    // necessary to know:
    //   (1) the object containing the reference.
    //   (1) the object containing the reference.
    //   (2) the specific property that contains the reference.
    //   (2) the specific property that contains the reference.
    //   (3) the object being referred to.
    //   (3) the object being referred to.
    // Binding a reference results in a new referrer entry in the
    // Binding a reference results in a new referrer entry in the
    // destination.
    // destination.
    void bind(CdlNode, CdlProperty, CdlNode);
    void bind(CdlNode, CdlProperty, CdlNode);
    // Unbinding a reference. Typically this only happens when the
    // Unbinding a reference. Typically this only happens when the
    // destination is unloaded. The arguments provide the source and
    // destination is unloaded. The arguments provide the source and
    // the source property.
    // the source property.
    void unbind(CdlNode, CdlProperty);
    void unbind(CdlNode, CdlProperty);
    // This is used by the ASSERT_CLASS() and ASSERT_THIS() macros.
    // This is used by the ASSERT_CLASS() and ASSERT_THIS() macros.
    bool check_this(cyg_assert_class_zeal cyg_quick) const;
    bool check_this(cyg_assert_class_zeal cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    // The data fields. The name is usually filled in by the
    // The data fields. The name is usually filled in by the
    // constructor. The destination defaults to zero for an unbound
    // constructor. The destination defaults to zero for an unbound
    // object and gets filled in by the bind() operation.
    // object and gets filled in by the bind() operation.
    std::string dest_name;
    std::string dest_name;
    CdlNode     dest;
    CdlNode     dest;
    enum {
    enum {
        CdlReference_Invalid = 0,
        CdlReference_Invalid = 0,
        CdlReference_Magic   = 0x3f908608
        CdlReference_Magic   = 0x3f908608
    } cdlreference_cookie;
    } cdlreference_cookie;
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The CdlNode class (and hence just about everything) contains a
// The CdlNode class (and hence just about everything) contains a
// vector of CdlReferrer objects. This keeps track of all entities
// vector of CdlReferrer objects. This keeps track of all entities
// that refer to this one, so if the value associated with this
// that refer to this one, so if the value associated with this
// changes it is possible to work out the impact of this on all
// changes it is possible to work out the impact of this on all
// entities that rely on this value.
// entities that rely on this value.
//
//
// Arguably this should work in terms of CdlValuable objects rather
// Arguably this should work in terms of CdlValuable objects rather
// than CdlNode objects. However it is convenient to use references
// than CdlNode objects. However it is convenient to use references
// for the connection between e.g. an option and a dialog, where
// for the connection between e.g. an option and a dialog, where
// there is no value involved. The reverse connection is of little
// there is no value involved. The reverse connection is of little
// use in this circumstance.
// use in this circumstance.
//
//
// CdlReferrer objects are rarely accessed directly. Instead they will
// CdlReferrer objects are rarely accessed directly. Instead they will
// be filled in during a CdlReference::bind() operation and erased
// be filled in during a CdlReference::bind() operation and erased
// during a CdlReference::unbind() operation. The only operations that
// during a CdlReference::unbind() operation. The only operations that
// should be public allow access to the contained data.
// should be public allow access to the contained data.
class CdlReferrer {
class CdlReferrer {
    friend class        CdlTest;
    friend class        CdlTest;
    // CdlReference::bind() and unbind() have direct access to the
    // CdlReference::bind() and unbind() have direct access to the
    // members, since these two functions are really responsible for
    // members, since these two functions are really responsible for
    // creating and destroying referrer objects.
    // creating and destroying referrer objects.
    friend class        CdlReference;
    friend class        CdlReference;
  public:
  public:
    // The default constructor, copy constructor and assignment
    // The default constructor, copy constructor and assignment
    // operator are all public to avoid problems with having vectors
    // operator are all public to avoid problems with having vectors
    // of referrer objects. Similarly the destructor is public.
    // of referrer objects. Similarly the destructor is public.
    // In practice updates actually happen as a consequence of
    // In practice updates actually happen as a consequence of
    // CdlReference::bind() and CdlReference::unbind().
    // CdlReference::bind() and CdlReference::unbind().
    CdlReferrer();
    CdlReferrer();
    CdlReferrer(const CdlReferrer&);
    CdlReferrer(const CdlReferrer&);
    CdlReferrer& operator=(const CdlReferrer&);
    CdlReferrer& operator=(const CdlReferrer&);
    ~CdlReferrer();
    ~CdlReferrer();
    CdlNode     get_source() const;
    CdlNode     get_source() const;
    CdlProperty get_source_property() const;
    CdlProperty get_source_property() const;
    void        update(CdlTransaction, CdlNode, CdlUpdate);
    void        update(CdlTransaction, CdlNode, CdlUpdate);
    bool        check_this(cyg_assert_class_zeal=cyg_quick) const;
    bool        check_this(cyg_assert_class_zeal=cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    CdlNode     source;
    CdlNode     source;
    CdlProperty source_property;
    CdlProperty source_property;
    enum {
    enum {
        CdlReferrer_Invalid = 0,
        CdlReferrer_Invalid = 0,
        CdlReferrer_Magic   = 0x70e1fc37
        CdlReferrer_Magic   = 0x70e1fc37
    } cdlreferrer_cookie;
    } cdlreferrer_cookie;
};
};
//}}}
//}}}
//{{{  Value and Expression  classes
//{{{  Value and Expression  classes
//{{{  CdlEvalContext
//{{{  CdlEvalContext
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Expression evaluation always happens within a certain context.
// Expression evaluation always happens within a certain context.
// This may involve a transaction. Usually it involves a node and
// This may involve a transaction. Usually it involves a node and
// a property within that node, although it is possible to evaluate
// a property within that node, although it is possible to evaluate
// expressions from inside Tcl code.
// expressions from inside Tcl code.
//
//
// To avoid passing too many arguments around the various
// To avoid passing too many arguments around the various
// evaluation-related routines, a utility class is provided.
// evaluation-related routines, a utility class is provided.
class CdlEvalContext {
class CdlEvalContext {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlTransaction      transaction;
    CdlTransaction      transaction;
    CdlNode             node;
    CdlNode             node;
    CdlProperty         property;
    CdlProperty         property;
    CdlToplevel         toplevel;
    CdlToplevel         toplevel;
    CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
    CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
    ~CdlEvalContext();
    ~CdlEvalContext();
    // Given a reference inside an expression, try to resolve this to either
    // Given a reference inside an expression, try to resolve this to either
    // a node or, more specifically, a valuable.
    // a node or, more specifically, a valuable.
    CdlNode             resolve_reference(CdlExpression, int);
    CdlNode             resolve_reference(CdlExpression, int);
    CdlValuable         resolve_valuable_reference(CdlExpression, int);
    CdlValuable         resolve_valuable_reference(CdlExpression, int);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    // Illegal operation, the three fields must always be supplied,
    // Illegal operation, the three fields must always be supplied,
    // although they may be zero.
    // although they may be zero.
    CdlEvalContext();
    CdlEvalContext();
    enum {
    enum {
        CdlEvalContext_Invalid  = 0,
        CdlEvalContext_Invalid  = 0,
        CdlEvalContext_Magic    = 0x03434be9
        CdlEvalContext_Magic    = 0x03434be9
    } cdlevalcontext_cookie;
    } cdlevalcontext_cookie;
};
};
//}}}
//}}}
//{{{  CdlSimpleValue
//{{{  CdlSimpleValue
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Expression evaluation happens in terms of CdlSimpleValue objects.
// Expression evaluation happens in terms of CdlSimpleValue objects.
// In CDL all values are strings, but for the purposes of arithmetic
// In CDL all values are strings, but for the purposes of arithmetic
// these strings sometimes have to be interpreted as integers or as
// these strings sometimes have to be interpreted as integers or as
// double precision numbers. Sometimes there is a choice, for example
// double precision numbers. Sometimes there is a choice, for example
// the equality operator == can mean numerical or string comparison.
// the equality operator == can mean numerical or string comparison.
// The basic rules that get applied are:
// The basic rules that get applied are:
//
//
//    1) if the current value has an integer representation then
//    1) if the current value has an integer representation then
//       use this by preference. This means that an expression
//       use this by preference. This means that an expression
//       of the form (CYGNUM_XXX != 0x100) will do a integer
//       of the form (CYGNUM_XXX != 0x100) will do a integer
//       comparison if possible.
//       comparison if possible.
//
//
//    2) otherwise if the current value can be interpreted as a
//    2) otherwise if the current value can be interpreted as a
//       double precision number, use that representation.
//       double precision number, use that representation.
//       All integers can be interpreted as doubles (at the risk
//       All integers can be interpreted as doubles (at the risk
//       of some loss of precision), so the representation as
//       of some loss of precision), so the representation as
//       a double should only be used if the integer representation
//       a double should only be used if the integer representation
//       is inappropriate.
//       is inappropriate.
//
//
//    3) otherwise interpret the value as a string.
//    3) otherwise interpret the value as a string.
//
//
// The default value is 0.
// The default value is 0.
class CdlSimpleValue {
class CdlSimpleValue {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlSimpleValue();
    CdlSimpleValue();
    CdlSimpleValue(std::string);
    CdlSimpleValue(std::string);
    CdlSimpleValue(cdl_int);
    CdlSimpleValue(cdl_int);
    CdlSimpleValue(double);
    CdlSimpleValue(double);
    CdlSimpleValue(const CdlSimpleValue&);
    CdlSimpleValue(const CdlSimpleValue&);
    CdlSimpleValue(bool);
    CdlSimpleValue(bool);
    ~CdlSimpleValue();
    ~CdlSimpleValue();
    CdlSimpleValue&     operator=(const CdlSimpleValue&);
    CdlSimpleValue&     operator=(const CdlSimpleValue&);
    CdlSimpleValue&     operator=(std::string);
    CdlSimpleValue&     operator=(std::string);
    CdlSimpleValue&     operator=(cdl_int);
    CdlSimpleValue&     operator=(cdl_int);
    CdlSimpleValue&     operator=(double);
    CdlSimpleValue&     operator=(double);
    CdlSimpleValue&     operator=(bool);
    CdlSimpleValue&     operator=(bool);
    bool                operator==(const CdlSimpleValue&) const;
    bool                operator==(const CdlSimpleValue&) const;
    bool                operator!=(const CdlSimpleValue&) const;
    bool                operator!=(const CdlSimpleValue&) const;
    bool                operator==(std::string arg) const
    bool                operator==(std::string arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this == val;
        return *this == val;
    }
    }
    bool                operator==(cdl_int arg) const
    bool                operator==(cdl_int arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this == val;
        return *this == val;
    }
    }
    bool                operator==(double arg) const
    bool                operator==(double arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this == val;
        return *this == val;
    }
    }
    bool                operator!=(std::string arg) const
    bool                operator!=(std::string arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this != val;
        return *this != val;
    }
    }
    bool                operator!=(cdl_int arg) const
    bool                operator!=(cdl_int arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this != val;
        return *this != val;
    }
    }
    bool                operator!=(double arg) const
    bool                operator!=(double arg) const
    {
    {
        CdlSimpleValue val(arg);
        CdlSimpleValue val(arg);
        return *this != val;
        return *this != val;
    }
    }
    void                set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
    void                set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
    std::string         get_value() const;
    std::string         get_value() const;
    bool                has_integer_value() const;
    bool                has_integer_value() const;
    void                set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
    void                set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
    cdl_int             get_integer_value() const;
    cdl_int             get_integer_value() const;
    bool                has_double_value() const;
    bool                has_double_value() const;
    void                set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
    void                set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
    double              get_double_value() const;
    double              get_double_value() const;
    CdlValueFormat      get_value_format() const;
    CdlValueFormat      get_value_format() const;
    void                set_value_format(CdlValueFormat);
    void                set_value_format(CdlValueFormat);
    void                set_value_format(CdlSimpleValue&);
    void                set_value_format(CdlSimpleValue&);
    void                set_value_format(CdlSimpleValue&, CdlSimpleValue&);
    void                set_value_format(CdlSimpleValue&, CdlSimpleValue&);
    static void         eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
    static void         eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
    // For expression evaluation, it is often convenient to get hold
    // For expression evaluation, it is often convenient to get hold
    // of a boolean as well. This may indicate a non-empty string
    // of a boolean as well. This may indicate a non-empty string
    // or a non-zero value.
    // or a non-zero value.
    bool                get_bool_value() const;
    bool                get_bool_value() const;
    // This class is too simple to warrant even a cookie validation.
    // This class is too simple to warrant even a cookie validation.
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
        return true;
        return true;
    }
    }
  protected:
  protected:
  private:
  private:
    enum {
    enum {
        int_valid       = 0x01,
        int_valid       = 0x01,
        double_valid    = 0x02,
        double_valid    = 0x02,
        string_valid    = 0x04,
        string_valid    = 0x04,
        int_invalid     = 0x08,
        int_invalid     = 0x08,
        double_invalid  = 0x10
        double_invalid  = 0x10
    };
    };
    mutable int         valid_flags;
    mutable int         valid_flags;
    mutable std::string value;
    mutable std::string value;
    mutable cdl_int     int_value;
    mutable cdl_int     int_value;
    mutable double      double_value;
    mutable double      double_value;
    CdlValueFormat      format;
    CdlValueFormat      format;
};
};
//}}}
//}}}
//{{{  CdlListValue
//{{{  CdlListValue
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Evaluating a list expression results in a set of possible values, but
// Evaluating a list expression results in a set of possible values, but
// unlike the original list expression these values are now constant and
// unlike the original list expression these values are now constant and
// can have no dependencies on CDL entities. As with list expressions the
// can have no dependencies on CDL entities. As with list expressions the
// main operation on a list value is to detect membership, but using
// main operation on a list value is to detect membership, but using
// list values allows multiple potential members to be tested without
// list values allows multiple potential members to be tested without
// repeated expression evaluation. The main use of list values is implicit
// repeated expression evaluation. The main use of list values is implicit
// in libcdl, each list expression contains a mutable cached list value.
// in libcdl, each list expression contains a mutable cached list value.
//
//
// A list value contains five sets of data:
// A list value contains five sets of data:
//
//
// 1) separate vectors of strings, integers, and floating point constants.
// 1) separate vectors of strings, integers, and floating point constants.
//    Having separate vectors of integers and floating points avoids
//    Having separate vectors of integers and floating points avoids
//    problems when numbers can be represented in different formats.
//    problems when numbers can be represented in different formats.
// 2) a vector of cdl_int pairs for ranges of integer data
// 2) a vector of cdl_int pairs for ranges of integer data
// 3) a vector of double pairs for ranges of floating point data
// 3) a vector of double pairs for ranges of floating point data
//
//
// Any of these vectors may be empty, but at least one of the vectors should
// Any of these vectors may be empty, but at least one of the vectors should
// contain useful data. Possibly there should also be tables for cdl_int and
// contain useful data. Possibly there should also be tables for cdl_int and
// double to avoid unnecessary string conversions.
// double to avoid unnecessary string conversions.
class CdlListValue {
class CdlListValue {
    friend class        CdlTest;
    friend class        CdlTest;
    // A list value will only be filled in when a list expression is evaluated.
    // A list value will only be filled in when a list expression is evaluated.
    // The members cannot be updated by other means.
    // The members cannot be updated by other means.
    friend class        CdlListExpressionBody;
    friend class        CdlListExpressionBody;
  public:
  public:
    CdlListValue();
    CdlListValue();
    ~CdlListValue();
    ~CdlListValue();
    CdlListValue(const CdlListValue&);
    CdlListValue(const CdlListValue&);
    CdlListValue& operator=(const CdlListValue&);
    CdlListValue& operator=(const CdlListValue&);
    bool        is_member(CdlSimpleValue&) const;
    bool        is_member(CdlSimpleValue&) const;
    bool        is_member(std::string, bool = true) const;
    bool        is_member(std::string, bool = true) const;
    bool        is_member(cdl_int, bool = true) const;
    bool        is_member(cdl_int, bool = true) const;
    bool        is_member(double, bool = true) const;
    bool        is_member(double, bool = true) const;
    // These provide access to the raw data, for example if it is
    // These provide access to the raw data, for example if it is
    // necessary to suggest a legal value to the user.
    // necessary to suggest a legal value to the user.
    const std::vector&                get_table() const;
    const std::vector&                get_table() const;
    const std::vector >&  get_integer_ranges() const;
    const std::vector >&  get_integer_ranges() const;
    const std::vector >&    get_double_ranges() const;
    const std::vector >&    get_double_ranges() const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    std::vector                 table;
    std::vector                 table;
    std::vector >   integer_ranges;
    std::vector >   integer_ranges;
    std::vector >     double_ranges;
    std::vector >     double_ranges;
    enum {
    enum {
        CdlListValue_Invalid  = 0,
        CdlListValue_Invalid  = 0,
        CdlListValue_Magic    = 0x2183a943
        CdlListValue_Magic    = 0x2183a943
    } cdllistvalue_cookie;
    } cdllistvalue_cookie;
};
};
//}}}
//}}}
//{{{  CdlValue
//{{{  CdlValue
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Values in CDL are non-trivial compared with some other languages.
// Values in CDL are non-trivial compared with some other languages.
// Even though CDL is not a fully-typed language, it does still have
// Even though CDL is not a fully-typed language, it does still have
// four different flavors to consider. There is also the problem that
// four different flavors to consider. There is also the problem that
// an entity may have up to four different values which should be
// an entity may have up to four different values which should be
// stored (default, inferred, wizard, user), with the ability to
// stored (default, inferred, wizard, user), with the ability to
// switch between them. The CdlValue class provides support for this.
// switch between them. The CdlValue class provides support for this.
//
//
// CdlValue objects are not normally updated explicitly. Instead
// CdlValue objects are not normally updated explicitly. Instead
// higher level code deals with CdlValuable objects, which inherit
// higher level code deals with CdlValuable objects, which inherit
// privately from CdlValue. Modifications to CdlValuables happen in
// privately from CdlValue. Modifications to CdlValuables happen in
// the context of a transaction.
// the context of a transaction.
//
//
// The first concept to take into account is the flavor. There
// The first concept to take into account is the flavor. There
// are four flavors, None, Bool, BoolData and Data. The member
// are four flavors, None, Bool, BoolData and Data. The member
// function get_flavor() can be used to obtain the current flavor.
// function get_flavor() can be used to obtain the current flavor.
//
//
//     CdlValueFlavor CdlValue::get_flavor() const;
//     CdlValueFlavor CdlValue::get_flavor() const;
//
//
// Values may be enabled or disabled. Values of flavor None
// Values may be enabled or disabled. Values of flavor None
// and Data are always enabled. Values of flavor Bool or BoolData
// and Data are always enabled. Values of flavor Bool or BoolData
// may or may not be enabled, by default they are disabled.
// may or may not be enabled, by default they are disabled.
//
//
//     bool CdlValue::is_enabled(...) const;
//     bool CdlValue::is_enabled(...) const;
//
//
// (The optional argument to is_enabled() is discussed later).
// (The optional argument to is_enabled() is discussed later).
//
//
// Values of flavor BoolData and Data also have a string value,
// Values of flavor BoolData and Data also have a string value,
// which can be interpreted as an integer or a double under
// which can be interpreted as an integer or a double under
// the right circumstances.
// the right circumstances.
//
//
//     std::string CdlValue::get_value(...) const;
//     std::string CdlValue::get_value(...) const;
//     bool        CdlValue::has_integer_value(...) const;
//     bool        CdlValue::has_integer_value(...) const;
//     bool        CdlValue::has_double_value(...) const;
//     bool        CdlValue::has_double_value(...) const;
//     cdl_int     CdlValue::get_integer_value(...) const;
//     cdl_int     CdlValue::get_integer_value(...) const;
//     double      CdlValue::get_double_value(...) const;
//     double      CdlValue::get_double_value(...) const;
//
//
// This is equivalent to a CdlSimpleValue object, and in fact
// This is equivalent to a CdlSimpleValue object, and in fact
// that is the internal representation. It is possible to
// that is the internal representation. It is possible to
// get hold of the CdlSimpleValue object directly:
// get hold of the CdlSimpleValue object directly:
//
//
//     CdlSimpleValue CdlValue::get_simple_value(...) const;
//     CdlSimpleValue CdlValue::get_simple_value(...) const;
//
//
// The get_integer_value() and get_double_value() members should
// The get_integer_value() and get_double_value() members should
// only be used if you are confident that the current value has
// only be used if you are confident that the current value has
// an integer or double representation. Otherwise the result is
// an integer or double representation. Otherwise the result is
// undefined.
// undefined.
//
//
// The optional argument to these member functions represents
// The optional argument to these member functions represents
// the source. A value can be set from four different sources:
// the source. A value can be set from four different sources:
// the default value (usually either 0 or the result of
// the default value (usually either 0 or the result of
// evaluating a default_value property); an inferred value,
// evaluating a default_value property); an inferred value,
// determined by the inference engine; a wizard value, i.e.
// determined by the inference engine; a wizard value, i.e.
// what a CDL wizard believes the correct value to be based
// what a CDL wizard believes the correct value to be based
// on user input; and a user value, something explicitly
// on user input; and a user value, something explicitly
// set by the end user. These have different priorities:
// set by the end user. These have different priorities:
// the inference engine can override default values but not
// the inference engine can override default values but not
// user values. A CdlValue object keeps track of the current
// user values. A CdlValue object keeps track of the current
// source.
// source.
//
//
//    CdlValueSource CdlValue::get_source() const;
//    CdlValueSource CdlValue::get_source() const;
//
//
// If no argument is given to e.g. is_enabled() then the
// If no argument is given to e.g. is_enabled() then the
// current source is used. Otherwise it is possible to find
// current source is used. Otherwise it is possible to find
// out whether or not the entity is enabled for each of the
// out whether or not the entity is enabled for each of the
// sources.
// sources.
//
//
// The default source is always defined, the others may or
// The default source is always defined, the others may or
// may not be. It is possible to find out for each source
// may not be. It is possible to find out for each source
// whether or not a value has been set.
// whether or not a value has been set.
//
//
//   bool CdlValue::has_source(CdlValueSource) const;
//   bool CdlValue::has_source(CdlValueSource) const;
//
//
//
//
// Updating values normally happens in the CdlValuable class,
// Updating values normally happens in the CdlValuable class,
// but the member functions are the same. There is a member
// but the member functions are the same. There is a member
// function to change the flavor:
// function to change the flavor:
//
//
//   void CdlValue::set_flavor(CdlValueFlavor);
//   void CdlValue::set_flavor(CdlValueFlavor);
//
//
// However this member function is intended only for use by the
// However this member function is intended only for use by the
// library itself. An entity's flavor is normally defined by CDL data,
// library itself. An entity's flavor is normally defined by CDL data,
// and should not be updated explicitly by application code.
// and should not be updated explicitly by application code.
//
//
// There are two member functions to manipulate the value source:
// There are two member functions to manipulate the value source:
//
//
//     void CdlValue::set_source(CdlValueSource);
//     void CdlValue::set_source(CdlValueSource);
//     void CdlValue::invalidate_source(CdlValueSource);
//     void CdlValue::invalidate_source(CdlValueSource);
//
//
// The first function can be used if e.g. the user wants to
// The first function can be used if e.g. the user wants to
// change his or her mind and go back to the default value
// change his or her mind and go back to the default value
// rather than a user value. The user value is not forgotten
// rather than a user value. The user value is not forgotten
// and can be reinstated.
// and can be reinstated.
//
//
// invalidate_source() can be used to completely cancel a
// invalidate_source() can be used to completely cancel a
// value source. If that source happens to be the current one
// value source. If that source happens to be the current one
// then the current source will be adjusted appropriately.
// then the current source will be adjusted appropriately.
// It is illegal to attempt to invalidate the default source.
// It is illegal to attempt to invalidate the default source.
//
//
// For values with flavor Bool and BoolData, there are three
// For values with flavor Bool and BoolData, there are three
// member functions that can be used to control the enabled
// member functions that can be used to control the enabled
// status:
// status:
//
//
//   void CdlValue::set_enabled(bool, CdlValueSource);
//   void CdlValue::set_enabled(bool, CdlValueSource);
//   void CdlValue::enable(CdlValueSource);
//   void CdlValue::enable(CdlValueSource);
//   void CdlValue::disable(CdlValueSource);
//   void CdlValue::disable(CdlValueSource);
//
//
// Note that when updating a CdlValue object the source should
// Note that when updating a CdlValue object the source should
// be known and must be specified. If the source has a higher
// be known and must be specified. If the source has a higher
// priority than the current one then it will automatically
// priority than the current one then it will automatically
// become the new source. On the rare occasion that this is
// become the new source. On the rare occasion that this is
// not desired, set_source() will have to be used afterwards
// not desired, set_source() will have to be used afterwards
// to reset the current source.
// to reset the current source.
//
//
// For values with flavor BoolData and Data the following
// For values with flavor BoolData and Data the following
// member functions are available to change the value string:
// member functions are available to change the value string:
//
//
//   void CdlValue::set_value(std::string, CdlValueSource);
//   void CdlValue::set_value(std::string, CdlValueSource);
//   void CdlValue::set_value(cdl_int, CdlValueSource);
//   void CdlValue::set_value(cdl_int, CdlValueSource);
//   void CdlValue::set_value(double, CdlvalueSource);
//   void CdlValue::set_value(double, CdlvalueSource);
//   void CdlValue::set_value(CdlSimpleValue&, CdlValueSource);
//   void CdlValue::set_value(CdlSimpleValue&, CdlValueSource);
//
//
// For values with flavor BoolData is is possible to
// For values with flavor BoolData is is possible to
// combine updating the enabled flag and the string value:
// combine updating the enabled flag and the string value:
//
//
//   void CdlValue::set_enabled_and_value(bool, std::string, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, std::string, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, cdl_int, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, cdl_int, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, double, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, double, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
//   void CdlValue::set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
//   void CdlValue::enable_and_set_value(std::string, CdlValueSource);
//   void CdlValue::enable_and_set_value(std::string, CdlValueSource);
//   void CdlValue::enable_and_set_value(cdl_int, CdlValueSource);
//   void CdlValue::enable_and_set_value(cdl_int, CdlValueSource);
//   void CdlValue::enable_and_set_value(double, CdlValueSource);
//   void CdlValue::enable_and_set_value(double, CdlValueSource);
//   void CdlValue::enable_and_set_value(CdlSimpleValue&, CdlValueSource);
//   void CdlValue::enable_and_set_value(CdlSimpleValue&, CdlValueSource);
//   void CdlValue::disable_and_set_value(std::string, CdlValueSource);
//   void CdlValue::disable_and_set_value(std::string, CdlValueSource);
//   void CdlValue::disable_and_set_value(cdl_int, CdlValueSource);
//   void CdlValue::disable_and_set_value(cdl_int, CdlValueSource);
//   void CdlValue::disable_and_set_value(double, CdlValueSource);
//   void CdlValue::disable_and_set_value(double, CdlValueSource);
//   void CdlValue::disable_and_set_value(CdlSimpleValue&, CdlValueSource);
//   void CdlValue::disable_and_set_value(CdlSimpleValue&, CdlValueSource);
//
//
// Obviously many of these functions are just simple inlines.
// Obviously many of these functions are just simple inlines.
//
//
// There is one final member function:
// There is one final member function:
//
//
//   void CdlValue::set(CdlSimpleValue, CdlValueSource);
//   void CdlValue::set(CdlSimpleValue, CdlValueSource);
//
//
// This member function is defined to do the right thing,
// This member function is defined to do the right thing,
// whatever the flavor happens to be.
// whatever the flavor happens to be.
class CdlValue {
class CdlValue {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
    CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
    virtual ~CdlValue();
    virtual ~CdlValue();
    CdlValue(const CdlValue&);
    CdlValue(const CdlValue&);
    CdlValue&           operator=(const CdlValue&);
    CdlValue&           operator=(const CdlValue&);
    CdlValueFlavor      get_flavor() const;
    CdlValueFlavor      get_flavor() const;
    CdlValueSource      get_source() const;
    CdlValueSource      get_source() const;
    bool                has_source(CdlValueSource) const;
    bool                has_source(CdlValueSource) const;
    bool                is_enabled(CdlValueSource = CdlValueSource_Current) const;
    bool                is_enabled(CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value(CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value(CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value(CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value(CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(CdlValueSource = CdlValueSource_Current) const;
    void set_source(CdlValueSource);
    void set_source(CdlValueSource);
    void invalidate_source(CdlValueSource);
    void invalidate_source(CdlValueSource);
    void set_enabled(bool, CdlValueSource);
    void set_enabled(bool, CdlValueSource);
    void enable(CdlValueSource source)
    void enable(CdlValueSource source)
    {
    {
        set_enabled(true, source);
        set_enabled(true, source);
    }
    }
    void disable(CdlValueSource source)
    void disable(CdlValueSource source)
    {
    {
        set_enabled(false, source);
        set_enabled(false, source);
    }
    }
    void set_value(CdlSimpleValue&, CdlValueSource);
    void set_value(CdlSimpleValue&, CdlValueSource);
    void set_value(std::string data, CdlValueSource source)
    void set_value(std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_integer_value(cdl_int data, CdlValueSource source)
    void set_integer_value(cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_double_value(double data, CdlValueSource source)
    void set_double_value(double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, val, source);
        set_enabled_and_value(true, val, source);
    }
    }
    void enable_and_set_value(std::string data, CdlValueSource source)
    void enable_and_set_value(std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void enable_and_set_value(cdl_int data, CdlValueSource source)
    void enable_and_set_value(cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void enable_and_set_value(double data, CdlValueSource source)
    void enable_and_set_value(double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, val, source);
        set_enabled_and_value(false, val, source);
    }
    }
    void disable_and_set_value(std::string data, CdlValueSource source)
    void disable_and_set_value(std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void disable_and_set_value(cdl_int data, CdlValueSource source)
    void disable_and_set_value(cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void disable_and_set_value(double data, CdlValueSource source)
    void disable_and_set_value(double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void set(CdlSimpleValue&, CdlValueSource);
    void set(CdlSimpleValue&, CdlValueSource);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    // This should only be used by the library itself.
    // This should only be used by the library itself.
    void                set_flavor(CdlValueFlavor);
    void                set_flavor(CdlValueFlavor);
  protected:
  protected:
  private:
  private:
    CdlValueFlavor      flavor;
    CdlValueFlavor      flavor;
    CdlValueSource      current_source;
    CdlValueSource      current_source;
    // FIXME: a static const member should be used for the array
    // FIXME: a static const member should be used for the array
    // sizes, but VC++ does not support that part of the language.
    // sizes, but VC++ does not support that part of the language.
    // FIXME: std::bitset should be used here. Using lots of separate
    // FIXME: std::bitset should be used here. Using lots of separate
    // bools here is inefficient.
    // bools here is inefficient.
    bool                source_valid[4];
    bool                source_valid[4];
    bool                enabled[4];
    bool                enabled[4];
    CdlSimpleValue      values[4];
    CdlSimpleValue      values[4];
    enum {
    enum {
        CdlValue_Invalid = 0,
        CdlValue_Invalid = 0,
        CdlValue_Magic   = 0x41837960
        CdlValue_Magic   = 0x41837960
    } cdlvalue_cookie;
    } cdlvalue_cookie;
};
};
//}}}
//}}}
//{{{  CdlSubexpression
//{{{  CdlSubexpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Expressions come into existence primarily as the result of reading
// Expressions come into existence primarily as the result of reading
// in certain properties like default_value in CDL data. It is also
// in certain properties like default_value in CDL data. It is also
// possible for expressions to be generated and evaluated on the fly
// possible for expressions to be generated and evaluated on the fly
// inside Tcl code, but that is expected to be a comparatively rare
// inside Tcl code, but that is expected to be a comparatively rare
// events. Expression objects always live on the heap, usually only
// events. Expression objects always live on the heap, usually only
// in derived classes.
// in derived classes.
//
//
// An ordinary expression evaluates to a single value. There are two
// An ordinary expression evaluates to a single value. There are two
// other types of expression in the CDL language, goal expressions and
// other types of expression in the CDL language, goal expressions and
// list expression. A goal expression is essentially a set of ordinary
// list expression. A goal expression is essentially a set of ordinary
// expressions with implicit &&'s between them. A list expression
// expressions with implicit &&'s between them. A list expression
// is a set of expressions that can be evaluated to a constant vector,
// is a set of expressions that can be evaluated to a constant vector,
// plus pairs of expressions that constitute ranges. Again goal and
// plus pairs of expressions that constitute ranges. Again goal and
// list expressions only live on the heap.
// list expressions only live on the heap.
//
//
// Both parsing an evaluation involve tokens for the various
// Both parsing an evaluation involve tokens for the various
// operators. The inference engine, conflict reporting code, and
// operators. The inference engine, conflict reporting code, and
// other diagnostic code will also need to have ready access to
// other diagnostic code will also need to have ready access to
// this information. Hence it makes a bit more sense to have
// this information. Hence it makes a bit more sense to have
// the enum outside the expression class.
// the enum outside the expression class.
enum CdlExprOp {
enum CdlExprOp {
    CdlExprOp_Invalid           =  0,
    CdlExprOp_Invalid           =  0,
    CdlExprOp_EOD               =  1,   // End of data reached
    CdlExprOp_EOD               =  1,   // End of data reached
    CdlEXprOp_Command           =  2,   // [tcl code]
    CdlEXprOp_Command           =  2,   // [tcl code]
    CdlExprOp_Variable          =  3,   // $tcl_variable
    CdlExprOp_Variable          =  3,   // $tcl_variable
    CdlExprOp_StringConstant    =  4,   // "hello"
    CdlExprOp_StringConstant    =  4,   // "hello"
    CdlExprOp_IntegerConstant   =  5,   // 123
    CdlExprOp_IntegerConstant   =  5,   // 123
    CdlExprOp_DoubleConstant    =  6,   // 3.1415
    CdlExprOp_DoubleConstant    =  6,   // 3.1415
    CdlExprOp_Reference         =  7,   // CYGPKG_INFRA
    CdlExprOp_Reference         =  7,   // CYGPKG_INFRA
    CdlExprOp_Range             =  8,   // x to y
    CdlExprOp_Range             =  8,   // x to y
    CdlExprOp_Negate            =  9,   // -x
    CdlExprOp_Negate            =  9,   // -x
    CdlExprOp_Plus              = 10,   // +x
    CdlExprOp_Plus              = 10,   // +x
    CdlExprOp_LogicalNot        = 11,   // !x
    CdlExprOp_LogicalNot        = 11,   // !x
    CdlExprOp_BitNot            = 12,   // ~x
    CdlExprOp_BitNot            = 12,   // ~x
    CdlExprOp_Indirect          = 13,   // *x
    CdlExprOp_Indirect          = 13,   // *x
    CdlExprOp_Active            = 14,   // ?x
    CdlExprOp_Active            = 14,   // ?x
    CdlExprOp_Function          = 15,   // sin(x)
    CdlExprOp_Function          = 15,   // sin(x)
    CdlExprOp_Multiply          = 16,   // x * y
    CdlExprOp_Multiply          = 16,   // x * y
    CdlExprOp_Divide            = 17,   // x / y
    CdlExprOp_Divide            = 17,   // x / y
    CdlExprOp_Remainder         = 18,   // x % y
    CdlExprOp_Remainder         = 18,   // x % y
    CdlExprOp_Add               = 19,   // x + y
    CdlExprOp_Add               = 19,   // x + y
    CdlExprOp_Subtract          = 20,   // x - y
    CdlExprOp_Subtract          = 20,   // x - y
    CdlExprOp_LeftShift         = 21,   // x << y
    CdlExprOp_LeftShift         = 21,   // x << y
    CdlExprOp_RightShift        = 22,   // x >> y
    CdlExprOp_RightShift        = 22,   // x >> y
    CdlExprOp_LessThan          = 23,   // x < y
    CdlExprOp_LessThan          = 23,   // x < y
    CdlExprOp_LessEqual         = 24,   // x <= y
    CdlExprOp_LessEqual         = 24,   // x <= y
    CdlExprOp_GreaterThan       = 25,   // x > y
    CdlExprOp_GreaterThan       = 25,   // x > y
    CdlExprOp_GreaterEqual      = 26,   // x >= y
    CdlExprOp_GreaterEqual      = 26,   // x >= y
    CdlExprOp_Equal             = 27,   // x == y
    CdlExprOp_Equal             = 27,   // x == y
    CdlExprOp_NotEqual          = 28,   // x != y
    CdlExprOp_NotEqual          = 28,   // x != y
    CdlExprOp_BitAnd            = 29,   // x & y
    CdlExprOp_BitAnd            = 29,   // x & y
    CdlExprOp_BitXor            = 30,   // x ^ y
    CdlExprOp_BitXor            = 30,   // x ^ y
    CdlExprOp_BitOr             = 31,   // x | y
    CdlExprOp_BitOr             = 31,   // x | y
    CdlExprOp_And               = 32,   // x && y
    CdlExprOp_And               = 32,   // x && y
    CdlExprOp_Or                = 33,   // x || y
    CdlExprOp_Or                = 33,   // x || y
    CdlExprOp_Cond              = 34,   // x ? a : b
    CdlExprOp_Cond              = 34,   // x ? a : b
    CdlExprOp_StringConcat      = 35,   // x . y
    CdlExprOp_StringConcat      = 35,   // x . y
    CdlExprOp_Implies           = 36,   // x implies y
    CdlExprOp_Implies           = 36,   // x implies y
    CdlExprOp_Xor               = 37,   // x xor y
    CdlExprOp_Xor               = 37,   // x xor y
    CdlExprOp_Eqv               = 38    // x eqv y
    CdlExprOp_Eqv               = 38    // x eqv y
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A subexpression consists of an operation, possibly some constant
// A subexpression consists of an operation, possibly some constant
// data, and possibly indices into the subexpression vector.
// data, and possibly indices into the subexpression vector.
// Normally some unions would be used, but unions and objects such
// Normally some unions would be used, but unions and objects such
// as std::string do not mix, and the amount of memory involved is
// as std::string do not mix, and the amount of memory involved is
// not big enough to really worry about.
// not big enough to really worry about.
#define CdlFunction_MaxArgs     3
#define CdlFunction_MaxArgs     3
struct CdlSubexpression {
struct CdlSubexpression {
    CdlExprOp           op;
    CdlExprOp           op;
    CdlSimpleValue      constants;              // String, integer or double constant
    CdlSimpleValue      constants;              // String, integer or double constant
    int                 reference_index;        // iff CdlExprOp_Reference
    int                 reference_index;        // iff CdlExprOp_Reference
    int                 lhs_index;              // for all non-constant operators
    int                 lhs_index;              // for all non-constant operators
    int                 rhs_index;              // for binary and ternary operators only
    int                 rhs_index;              // for binary and ternary operators only
    int                 rrhs_index;             // only for ternary operators.
    int                 rrhs_index;             // only for ternary operators.
    int                 func;                   // iff CdlExprOp_Function
    int                 func;                   // iff CdlExprOp_Function
    int                 args[CdlFunction_MaxArgs];
    int                 args[CdlFunction_MaxArgs];
};
};
//}}}
//}}}
//{{{  CdlFunction
//{{{  CdlFunction
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Generic support for function parsing, evaluation, and inference. The
// Generic support for function parsing, evaluation, and inference. The
// implementation is extensible so that functions can be added to the
// implementation is extensible so that functions can be added to the
// core via static constructors.
// core via static constructors.
class CdlFunction {
class CdlFunction {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlFunction(const char* /* name */, int /* no_args */,
    CdlFunction(const char* /* name */, int /* no_args */,
                void (*)(CdlExpression, const CdlSubexpression&),
                void (*)(CdlExpression, const CdlSubexpression&),
                void (*)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
                void (*)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
                bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int),
                bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int),
                bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)
                bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)
                );
                );
    ~CdlFunction();
    ~CdlFunction();
    static bool         is_function(std::string, int&);
    static bool         is_function(std::string, int&);
    static std::string  get_name(int);
    static std::string  get_name(int);
    static int          get_args_count(int);
    static int          get_args_count(int);
    static void         check(CdlExpression, const CdlSubexpression&);
    static void         check(CdlExpression, const CdlSubexpression&);
    static void         eval(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
    static void         eval(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
    static bool         infer_bool(CdlTransaction, CdlExpression, unsigned int, bool, int);
    static bool         infer_bool(CdlTransaction, CdlExpression, unsigned int, bool, int);
    static bool         infer_value(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
    static bool         infer_value(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
    static void         (*null_check)(CdlExpression, const CdlSubexpression&);
    static void         (*null_check)(CdlExpression, const CdlSubexpression&);
    static bool         (*null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int);
    static bool         (*null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int);
    static bool         (*null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
    static bool         (*null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
  protected:
  protected:
  private:
  private:
    // Keep track of all functions in the system
    // Keep track of all functions in the system
    static std::vector    all_functions;
    static std::vector    all_functions;
    // Each function object is given a unique id during initialization
    // Each function object is given a unique id during initialization
    static int          next_id;
    static int          next_id;
    int                 id;
    int                 id;
    // Provided by the constructor
    // Provided by the constructor
    const char*         name;
    const char*         name;
    int                 number_args;
    int                 number_args;
    void                (*check_fn)(CdlExpression, const CdlSubexpression&);
    void                (*check_fn)(CdlExpression, const CdlSubexpression&);
    void                (*eval_fn)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
    void                (*eval_fn)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
    bool                (*infer_bool_fn)(CdlTransaction, CdlExpression, unsigned int, bool, int);
    bool                (*infer_bool_fn)(CdlTransaction, CdlExpression, unsigned int, bool, int);
    bool                (*infer_value_fn)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
    bool                (*infer_value_fn)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
    // The default constructor is illegal
    // The default constructor is illegal
    CdlFunction();
    CdlFunction();
};
};
//}}}
//}}}
//{{{  CdlExpression
//{{{  CdlExpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// And now for the expression class itself.
// And now for the expression class itself.
class CdlExpressionBody {
class CdlExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    // The default constructor is basically a no-op, new expression
    // The default constructor is basically a no-op, new expression
    // objects only get created as a consequence of parsing. However
    // objects only get created as a consequence of parsing. However
    // it exists and is protected for the convenience of derived
    // it exists and is protected for the convenience of derived
    // classes. The copy constructor is protected, allowing parsing
    // classes. The copy constructor is protected, allowing parsing
    // code to first parse an expression and then copy the expression
    // code to first parse an expression and then copy the expression
    // into a higher level object. The assignment operator is illegal.
    // into a higher level object. The assignment operator is illegal.
    // There is no reason to hide the destructor.
    // There is no reason to hide the destructor.
    virtual ~CdlExpressionBody();
    virtual ~CdlExpressionBody();
    // An expression involves three pieces of data. There is a vector
    // An expression involves three pieces of data. There is a vector
    // of subexpressions. It is also necessary to know where
    // of subexpressions. It is also necessary to know where
    // evaluation should being, in accordance with operator precedence
    // evaluation should being, in accordance with operator precedence
    // rules. And there is a vector of CdlReference objects - this
    // rules. And there is a vector of CdlReference objects - this
    // needs to be kept separate from the subexpression vector because
    // needs to be kept separate from the subexpression vector because
    // CdlReference objects are comparatively tricky.
    // CdlReference objects are comparatively tricky.
    //
    //
    // All of this data is public and can be readily inspected by the
    // All of this data is public and can be readily inspected by the
    // inference engine, by conflict detection code, by diagnostic
    // inference engine, by conflict detection code, by diagnostic
    // code, etc.
    // code, etc.
    std::vector       sub_expressions;
    std::vector       sub_expressions;
    int                                 first_subexpression;
    int                                 first_subexpression;
    std::vector           references;
    std::vector           references;
    bool                                update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    bool                                update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    // There are a number of parsing functions. The first one is
    // There are a number of parsing functions. The first one is
    // used by higher-level code to parse a single expression. Its
    // used by higher-level code to parse a single expression. Its
    // argument is a single string (which may be the result of
    // argument is a single string (which may be the result of
    // concatenating several Tcl arguments), and at the end of the
    // concatenating several Tcl arguments), and at the end of the
    // parse operation there should be no further data. The result
    // parse operation there should be no further data. The result
    // will either be a new expression object or a parsing exception
    // will either be a new expression object or a parsing exception
    // to be caught by higher level code.
    // to be caught by higher level code.
    static CdlExpression        parse(std::string);
    static CdlExpression        parse(std::string);
    // This is used when parsing list expressions, which involve a
    // This is used when parsing list expressions, which involve a
    // sequence of ordinary expressions and possibly range operators.
    // sequence of ordinary expressions and possibly range operators.
    // The whole list expression lives in a single string, and it is
    // The whole list expression lives in a single string, and it is
    // necessary to provide an index indicating where in the string
    // necessary to provide an index indicating where in the string
    // parsing should begin. It is also useful to return details of
    // parsing should begin. It is also useful to return details of
    // the token that caused parsing to terminate (EOD, Range, or
    // the token that caused parsing to terminate (EOD, Range, or
    // the start of something else).
    // the start of something else).
    static CdlExpression        parse(std::string, int&, CdlExprOp&, int&);
    static CdlExpression        parse(std::string, int&, CdlExprOp&, int&);
    // A goal expression is derived from an ordinary expression but
    // A goal expression is derived from an ordinary expression but
    // has somewhat different rules for evaluating. Parsing a goal
    // has somewhat different rules for evaluating. Parsing a goal
    // expression involves parsing a number of ordinary expressions
    // expression involves parsing a number of ordinary expressions
    // with implicit && operators between them, and it requires
    // with implicit && operators between them, and it requires
    // a parsing function that can be used to extend an existing
    // a parsing function that can be used to extend an existing
    // expression.
    // expression.
    //
    //
    // NOTE: possibly this should should be a protected member, since
    // NOTE: possibly this should should be a protected member, since
    // its main use is in parsing goal expressions.
    // its main use is in parsing goal expressions.
    static void continue_parse(CdlExpression, std::string, int&, CdlExprOp&, int&);
    static void continue_parse(CdlExpression, std::string, int&, CdlExprOp&, int&);
    // Evaluating expressions. Note that this may fail at run-time
    // Evaluating expressions. Note that this may fail at run-time
    // because of errors that cannot be caught sensibly when the
    // because of errors that cannot be caught sensibly when the
    // expression is read in, for example arithmetic overflow or
    // expression is read in, for example arithmetic overflow or
    // division by zero. Because such failures are a possibility
    // division by zero. Because such failures are a possibility
    // anyway no special action is taken to prevent an expression
    // anyway no special action is taken to prevent an expression
    // with e.g. an unresolved reference from being evaluated.
    // with e.g. an unresolved reference from being evaluated.
    //
    //
    // eval() is the public interface, and manages
    // eval() is the public interface, and manages
    // CdlConflict_EvalException objects. eval_internal() is for use
    // CdlConflict_EvalException objects. eval_internal() is for use
    // by list and goal expressions.
    // by list and goal expressions.
    void eval(CdlEvalContext&, CdlSimpleValue&);
    void eval(CdlEvalContext&, CdlSimpleValue&);
    void eval_internal(CdlEvalContext&, CdlSimpleValue&);
    void eval_internal(CdlEvalContext&, CdlSimpleValue&);
    void eval_subexpression(CdlEvalContext&, int, CdlSimpleValue&);
    void eval_subexpression(CdlEvalContext&, int, CdlSimpleValue&);
    // The full original expression is useful for diagnostics purposes
    // The full original expression is useful for diagnostics purposes
    std::string get_original_string() const;
    std::string get_original_string() const;
    bool        check_this(cyg_assert_class_zeal cyg_quick) const;
    bool        check_this(cyg_assert_class_zeal cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    // The default constructor does very little, the main work
    // The default constructor does very little, the main work
    // is done by the various parsing functions. However it is
    // is done by the various parsing functions. However it is
    // available to derived classes, especially goal expressions.
    // available to derived classes, especially goal expressions.
    CdlExpressionBody();
    CdlExpressionBody();
    // The copy constructor has to be usable by derived classes,
    // The copy constructor has to be usable by derived classes,
    // e.g. CdlExpressionProperty
    // e.g. CdlExpressionProperty
    CdlExpressionBody(const CdlExpressionBody&);
    CdlExpressionBody(const CdlExpressionBody&);
  private:
  private:
    // The assignment operator is illegal.
    // The assignment operator is illegal.
    CdlExpressionBody&  operator=(const CdlExpressionBody&);
    CdlExpressionBody&  operator=(const CdlExpressionBody&);
    // The string that was parsed originally
    // The string that was parsed originally
    std::string                 expression_string;
    std::string                 expression_string;
    enum {
    enum {
        CdlExpressionBody_Invalid       = 0,
        CdlExpressionBody_Invalid       = 0,
        CdlExpressionBody_Magic         = 0x760293a3
        CdlExpressionBody_Magic         = 0x760293a3
    } cdlexpressionbody_cookie;
    } cdlexpressionbody_cookie;
};
};
//}}}
//}}}
//{{{  CdlListExpression
//{{{  CdlListExpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The main use of list expressions is for the legal_values
// The main use of list expressions is for the legal_values
// properties. Essentially a list expression is just a vector of
// properties. Essentially a list expression is just a vector of
// ordinary expressions and ranges of expressions.
// ordinary expressions and ranges of expressions.
class CdlListExpressionBody {
class CdlListExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    // Availability of constructors etc. is as per the ordinary
    // Availability of constructors etc. is as per the ordinary
    // expression class.
    // expression class.
    virtual ~CdlListExpressionBody();
    virtual ~CdlListExpressionBody();
    // The data associated with a list expression is a vector of
    // The data associated with a list expression is a vector of
    // expressions, plus a vector of expression pairs constituting
    // expressions, plus a vector of expression pairs constituting
    // ranges. As with ordinary expressions the data is fully public
    // ranges. As with ordinary expressions the data is fully public
    // and can be readily examined by e.g. the inference engine.
    // and can be readily examined by e.g. the inference engine.
    std::vector                                  data;
    std::vector                                  data;
    std::vector >        ranges;
    std::vector >        ranges;
    // Parsing. This involves taking a single string, typically from
    // Parsing. This involves taking a single string, typically from
    // a CDL script, and parsing one or more ordinary expressions.
    // a CDL script, and parsing one or more ordinary expressions.
    static CdlListExpression parse(std::string);
    static CdlListExpression parse(std::string);
    // Evaluation support. A list expression evaluates to a list value.
    // Evaluation support. A list expression evaluates to a list value.
    void eval(CdlEvalContext&, CdlListValue&);
    void eval(CdlEvalContext&, CdlListValue&);
    // More commonly client code is going to be interested in whether
    // More commonly client code is going to be interested in whether
    // or not a particular value is a legal member. The result
    // or not a particular value is a legal member. The result
    // cache ensures that it is possible to
    // cache ensures that it is possible to
    bool is_member(CdlEvalContext&, CdlSimpleValue&);
    bool is_member(CdlEvalContext&, CdlSimpleValue&);
    bool is_member(CdlEvalContext&, std::string);
    bool is_member(CdlEvalContext&, std::string);
    bool is_member(CdlEvalContext&, cdl_int);
    bool is_member(CdlEvalContext&, cdl_int);
    bool is_member(CdlEvalContext&, double);
    bool is_member(CdlEvalContext&, double);
    // The full original expression is useful for diagnostics purposes
    // The full original expression is useful for diagnostics purposes
    std::string get_original_string() const;
    std::string get_original_string() const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlListExpressionBody(const CdlListExpressionBody&);
    CdlListExpressionBody(const CdlListExpressionBody&);
    bool        update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    bool        update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
  private:
  private:
    CdlListExpressionBody();
    CdlListExpressionBody();
    CdlListExpressionBody& operator=(const CdlListExpressionBody&);
    CdlListExpressionBody& operator=(const CdlListExpressionBody&);
    void eval_internal(CdlEvalContext&, CdlListValue&);
    void eval_internal(CdlEvalContext&, CdlListValue&);
    std::string         expression_string;
    std::string         expression_string;
    enum {
    enum {
        CdlListExpressionBody_Invalid   = 0,
        CdlListExpressionBody_Invalid   = 0,
        CdlListExpressionBody_Magic     = 0x7da4bcc2
        CdlListExpressionBody_Magic     = 0x7da4bcc2
    } cdllistexpressionbody_cookie;
    } cdllistexpressionbody_cookie;
};
};
//}}}
//}}}
//{{{  CdlGoalExpression
//{{{  CdlGoalExpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A goal expression inherits privately from ordinary expressions. Essentially
// A goal expression inherits privately from ordinary expressions. Essentially
// a goal expression is simply a set of ordinary expressions separated by &&,
// a goal expression is simply a set of ordinary expressions separated by &&,
// but it can only be evaluated to a boolean. The parse() and eval() members
// but it can only be evaluated to a boolean. The parse() and eval() members
// of the base class should not be exposed. There is a member to get hold of
// of the base class should not be exposed. There is a member to get hold of
// the underlying ordinary expression, for use by e.g. the inference engine.
// the underlying ordinary expression, for use by e.g. the inference engine.
class CdlGoalExpressionBody : private CdlExpressionBody {
class CdlGoalExpressionBody : private CdlExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
    typedef CdlExpressionBody inherited;
    typedef CdlExpressionBody inherited;
  public:
  public:
    virtual ~CdlGoalExpressionBody();
    virtual ~CdlGoalExpressionBody();
    static CdlGoalExpression parse(std::string);
    static CdlGoalExpression parse(std::string);
    // A few variants of the eval() member, with a choice of returning
    // A few variants of the eval() member, with a choice of returning
    // by value or by reference. The latter provide consistency with the
    // by value or by reference. The latter provide consistency with the
    // other expression classes.
    // other expression classes.
    bool eval(CdlEvalContext&);
    bool eval(CdlEvalContext&);
    void eval(CdlEvalContext&, bool&);
    void eval(CdlEvalContext&, bool&);
    // Provide public access to the underlying expression object,
    // Provide public access to the underlying expression object,
    // useful for the inference engine
    // useful for the inference engine
    CdlExpression               get_expression();
    CdlExpression               get_expression();
    // The full original expression is useful for diagnostics purposes
    // The full original expression is useful for diagnostics purposes
    std::string get_original_string() const;
    std::string get_original_string() const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlGoalExpressionBody(const CdlGoalExpressionBody&);
    CdlGoalExpressionBody(const CdlGoalExpressionBody&);
  private:
  private:
    CdlGoalExpressionBody();
    CdlGoalExpressionBody();
    CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
    CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
    void eval_internal(CdlEvalContext&, bool&);
    void eval_internal(CdlEvalContext&, bool&);
    std::string expression_string;
    std::string expression_string;
    enum {
    enum {
        CdlGoalExpressionBody_Invalid = 0,
        CdlGoalExpressionBody_Invalid = 0,
        CdlGoalExpressionBody_Magic   = 0x5a58bb24
        CdlGoalExpressionBody_Magic   = 0x5a58bb24
    } cdlgoalexpressionbody_cookie;
    } cdlgoalexpressionbody_cookie;
};
};
//}}}
//}}}
//{{{  CdlInfer
//{{{  CdlInfer
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A utility class related to inference. This exports the main functions
// A utility class related to inference. This exports the main functions
// needed, allowing e.g. per-function inference routines from func.cxx to
// needed, allowing e.g. per-function inference routines from func.cxx to
// interact with the main inference engine.
// interact with the main inference engine.
class CdlInfer {
class CdlInfer {
  public:
  public:
    static bool make_active(CdlTransaction, CdlNode, int /* level */);
    static bool make_active(CdlTransaction, CdlNode, int /* level */);
    static bool make_inactive(CdlTransaction, CdlNode, int /* level */);
    static bool make_inactive(CdlTransaction, CdlNode, int /* level */);
    static bool set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, int /* level */);
    static bool set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, int /* level */);
    static bool set_valuable_bool(CdlTransaction, CdlValuable, bool, int /* level */);
    static bool set_valuable_bool(CdlTransaction, CdlValuable, bool, int /* level */);
    static bool subexpr_value(CdlTransaction, CdlExpression, unsigned int /* index */, CdlSimpleValue& goal, int /* level */);
    static bool subexpr_value(CdlTransaction, CdlExpression, unsigned int /* index */, CdlSimpleValue& goal, int /* level */);
    static bool subexpr_bool(CdlTransaction, CdlExpression, unsigned int /* index */, bool, int /* level */);
    static bool subexpr_bool(CdlTransaction, CdlExpression, unsigned int /* index */, bool, int /* level */);
  private:
  private:
    CdlInfer();
    CdlInfer();
};
};
//}}}
//}}}
//}}}
//}}}
//{{{  CdlConflict classes
//{{{  CdlConflict classes
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// As a configuration is created and modified there will be times when
// As a configuration is created and modified there will be times when
// things are not completely consistent. There may be a reference to
// things are not completely consistent. There may be a reference to
// some option that is not in any package in the current
// some option that is not in any package in the current
// configuration. An option may have an invalid value, possibly as a
// configuration. An option may have an invalid value, possibly as a
// side effect of a change to some other option. There may be a
// side effect of a change to some other option. There may be a
// dependency that is not satisfied. There may be other types of
// dependency that is not satisfied. There may be other types of
// conflict.
// conflict.
//
//
// The library provides a base class CdlConflict, and a number of
// The library provides a base class CdlConflict, and a number of
// derived classes for common types of conflict such as unresolved
// derived classes for common types of conflict such as unresolved
// references. All conflicts are associated with a CdlNode and a
// references. All conflicts are associated with a CdlNode and a
// property within that. It is possible to use dynamic_cast<> to find
// property within that. It is possible to use dynamic_cast<> to find
// out the exact type of a conflict, or alternatively to use the
// out the exact type of a conflict, or alternatively to use the
// virtual member function get_explanation().
// virtual member function get_explanation().
//
//
// Conflicts may be disabled by the user if they are not actually
// Conflicts may be disabled by the user if they are not actually
// important as far as application code is concerned. In other words
// important as far as application code is concerned. In other words
// the end user is allowed to override the constraints specified in
// the end user is allowed to override the constraints specified in
// the CDL. This information is saved with the configuration data.
// the CDL. This information is saved with the configuration data.
// Preferably the user should give an explanation for why the conflict
// Preferably the user should give an explanation for why the conflict
// is disabled, to serve as a reminder some months later when the
// is disabled, to serve as a reminder some months later when the
// configuration is reloaded.
// configuration is reloaded.
//
//
//
//
// Conflicts have a fairly complicated life cycle. First it is
// Conflicts have a fairly complicated life cycle. First it is
// necessary to distinguish between structural and normal conflicts. A
// necessary to distinguish between structural and normal conflicts. A
// structural conflict is typically caused by a reference to a
// structural conflict is typically caused by a reference to a
// non-existent valuable. These conflicts are generally created only
// non-existent valuable. These conflicts are generally created only
// when something is loaded, and only go away when something is
// when something is loaded, and only go away when something is
// unloaded. A normal conflict is typically related to a value, for
// unloaded. A normal conflict is typically related to a value, for
// example a value outside the legal range, or a "requires" property
// example a value outside the legal range, or a "requires" property
// that is not satisfied.
// that is not satisfied.
//
//
// Conflicts are created and destroyed in the context of a
// Conflicts are created and destroyed in the context of a
// transaction, which in turn operates in the context of a toplevel.
// transaction, which in turn operates in the context of a toplevel.
// If the transaction is committed then new conflicts get added to the
// If the transaction is committed then new conflicts get added to the
// appropriate toplevel list, and destroyed conflicts get removed from
// appropriate toplevel list, and destroyed conflicts get removed from
// the toplevel list. The transaction field indicates whether the
// the toplevel list. The transaction field indicates whether the
// conflict is currently per-transaction or global.
// conflict is currently per-transaction or global.
//
//
// Transactions may get nested, i.e. a conflict may get created as
// Transactions may get nested, i.e. a conflict may get created as
// part of a sub-transaction, and when that sub-transaction is committed
// part of a sub-transaction, and when that sub-transaction is committed
// the conflict is moved to the parent transaction.
// the conflict is moved to the parent transaction.
//
//
// For each toplevel, libcdl keeps track of all conflicts. This only
// For each toplevel, libcdl keeps track of all conflicts. This only
// applies to committed conflicts, per-transaction conflicts are not
// applies to committed conflicts, per-transaction conflicts are not
// accessible in this way.
// accessible in this way.
//
//
// As part of a transaction, libcdl may attempt to find solutions for
// As part of a transaction, libcdl may attempt to find solutions for
// particular conflicts, and those solutions may get installed
// particular conflicts, and those solutions may get installed
// automatically. No attempt is made to keep track of solutions
// automatically. No attempt is made to keep track of solutions
// on a global basis, only on a per-transaction basis.
// on a global basis, only on a per-transaction basis.
class CdlConflictBody {
class CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
    // Transactions and conflicts are closely connected
    // Transactions and conflicts are closely connected
    friend class CdlTransactionBody;
    friend class CdlTransactionBody;
  public:
  public:
    // Creation happens only inside a derived class.
    // Creation happens only inside a derived class.
    // Clearing a conflict only happens inside transactions.
    // Clearing a conflict only happens inside transactions.
    // Destroying a conflict only happens from inside a
    // Destroying a conflict only happens from inside a
    // per-transaction clear(), or during a transaction commit.
    // per-transaction clear(), or during a transaction commit.
    // Is this conflict part of a transaction, or has it been committed to the toplevel.
    // Is this conflict part of a transaction, or has it been committed to the toplevel.
    CdlTransaction      get_transaction() const;
    CdlTransaction      get_transaction() const;
    // Is inference implemented for this type of conflict?
    // Is inference implemented for this type of conflict?
    virtual bool        resolution_implemented() const;
    virtual bool        resolution_implemented() const;
    // Try to resolve an existing global conflict. A new transaction
    // Try to resolve an existing global conflict. A new transaction
    // is created for this operation, the conflict is resolved within
    // is created for this operation, the conflict is resolved within
    // that transaction, and then CdlTransaction::body() is used to
    // that transaction, and then CdlTransaction::body() is used to
    // handle inference callbacks, commits, etc. See also
    // handle inference callbacks, commits, etc. See also
    // CdlToplevel::resolve_conflicts() and
    // CdlToplevel::resolve_conflicts() and
    // CdlToplevel::resolve_all_conflicts(). The conflict may cease to
    // CdlToplevel::resolve_all_conflicts(). The conflict may cease to
    // exist as a side-effect of this call.
    // exist as a side-effect of this call.
    void                resolve();
    void                resolve();
    // Keep track of whether or not this conflict has a solution
    // Keep track of whether or not this conflict has a solution
    // 1) a conflict may have a current solution. This gets invalidated
    // 1) a conflict may have a current solution. This gets invalidated
    //    whenever there is a change to a value that was referenced
    //    whenever there is a change to a value that was referenced
    //    while identifying the solution.
    //    while identifying the solution.
    //
    //
    //    A current solution is indicated by a non-empty solution vector.
    //    A current solution is indicated by a non-empty solution vector.
    //
    //
    // 2) a conflict may not have a current solution. Again this gets
    // 2) a conflict may not have a current solution. Again this gets
    //    invalidated whenever a referred value changes. There is a boolean
    //    invalidated whenever a referred value changes. There is a boolean
    //    to keep track of this.
    //    to keep track of this.
    //
    //
    // 3) a conflict may not have a current solution, but another run of
    // 3) a conflict may not have a current solution, but another run of
    //    the inference engine may find one.
    //    the inference engine may find one.
    bool                has_known_solution() const;
    bool                has_known_solution() const;
    bool                has_no_solution() const;
    bool                has_no_solution() const;
    const std::vector >& get_solution() const;
    const std::vector >& get_solution() const;
    const std::set& get_solution_references() const;
    const std::set& get_solution_references() const;
    void                clear_solution();
    void                clear_solution();
    // Provide a text message "explaining" the conflict.
    // Provide a text message "explaining" the conflict.
    // This only makes sense for derived classes.
    // This only makes sense for derived classes.
    virtual std::string get_explanation() const = 0;
    virtual std::string get_explanation() const = 0;
    // Basic information access.
    // Basic information access.
    CdlNode             get_node() const;
    CdlNode             get_node() const;
    CdlProperty         get_property() const;
    CdlProperty         get_property() const;
    bool                is_structural() const;
    bool                is_structural() const;
    // Enabling and disabling conflicts currently happens outside the
    // Enabling and disabling conflicts currently happens outside the
    // context of any transaction.
    // context of any transaction.
    // FIXME: these are not currently implemented. It would be necessary
    // FIXME: these are not currently implemented. It would be necessary
    // to store the information in the savefile, which requires an
    // to store the information in the savefile, which requires an
    // unambiguous way of identifying a conflict that is likely to
    // unambiguous way of identifying a conflict that is likely to
    // survice package version changes.
    // survice package version changes.
    void                disable(std::string);
    void                disable(std::string);
    void                enable();
    void                enable();
    bool                is_enabled() const;
    bool                is_enabled() const;
    std::string         get_disabled_reason() const;
    std::string         get_disabled_reason() const;
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
    CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
    // The destructor gets accessed from inside the friend transaction class,
    // The destructor gets accessed from inside the friend transaction class,
    // either during a clear_conflict() or during a transaction commit.
    // either during a clear_conflict() or during a transaction commit.
    virtual ~CdlConflictBody();
    virtual ~CdlConflictBody();
    // All conflicts are associated with a node and a property.
    // All conflicts are associated with a node and a property.
    // This information will be useful to derived classes'
    // This information will be useful to derived classes'
    // implementations of get_explanation()
    // implementations of get_explanation()
    CdlNode             node;
    CdlNode             node;
    CdlProperty         property;
    CdlProperty         property;
  private:
  private:
    // Attempt to resolve a conflict in a sub-transaction
    // Attempt to resolve a conflict in a sub-transaction
    // This is invoked from inside the transaction resolve code.
    // This is invoked from inside the transaction resolve code.
    // There are additional exported interfaces inside and outside
    // There are additional exported interfaces inside and outside
    // the transaction class.
    // the transaction class.
    virtual bool        inner_resolve(CdlTransaction, int);
    virtual bool        inner_resolve(CdlTransaction, int);
    // Keep track of the transaction in which this conflict was created.
    // Keep track of the transaction in which this conflict was created.
    // The field is cleared at the end of a transaction.
    // The field is cleared at the end of a transaction.
    CdlTransaction      transaction;
    CdlTransaction      transaction;
    // Usually the derived class will decide whether or not
    // Usually the derived class will decide whether or not
    // this conflict is structural in nature, but the data
    // this conflict is structural in nature, but the data
    // needs to be available at base constructor time so
    // needs to be available at base constructor time so
    // a virtual function is not appropriate.
    // a virtual function is not appropriate.
    bool                structural;
    bool                structural;
    // Solution support
    // Solution support
    bool                                           no_solution;
    bool                                           no_solution;
    std::vector > solution;
    std::vector > solution;
    std::set                          solution_references;
    std::set                          solution_references;
    void update_solution_validity(CdlValuable);
    void update_solution_validity(CdlValuable);
    // Users may disable a conflict. Usually they will have to
    // Users may disable a conflict. Usually they will have to
    // supply a reason for this.
    // supply a reason for this.
    bool                enabled;
    bool                enabled;
    std::string         reason;
    std::string         reason;
    enum {
    enum {
        CdlConflictBody_Invalid = 0,
        CdlConflictBody_Invalid = 0,
        CdlConflictBody_Magic   = 0x073e8853
        CdlConflictBody_Magic   = 0x073e8853
    } cdlconflictbody_cookie;
    } cdlconflictbody_cookie;
    // Illegal operations. Conflicts always live on the heap.
    // Illegal operations. Conflicts always live on the heap.
    CdlConflictBody();
    CdlConflictBody();
    CdlConflictBody(const CdlConflictBody&);
    CdlConflictBody(const CdlConflictBody&);
    CdlConflictBody& operator=(const CdlConflictBody&);
    CdlConflictBody& operator=(const CdlConflictBody&);
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// An unresolved conflict means that there is a reference in some
// An unresolved conflict means that there is a reference in some
// property to an entity that is not yet in the current configuration.
// property to an entity that is not yet in the current configuration.
// The class provides convenient access to the name of the unresolved
// The class provides convenient access to the name of the unresolved
// entity.
// entity.
class CdlConflict_UnresolvedBody : public CdlConflictBody {
class CdlConflict_UnresolvedBody : public CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string         get_target_name() const;
    std::string         get_target_name() const;
    std::string         get_explanation() const;
    std::string         get_explanation() const;
    static bool         test(CdlConflict);
    static bool         test(CdlConflict);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    virtual ~CdlConflict_UnresolvedBody();
    virtual ~CdlConflict_UnresolvedBody();
    CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string         target_name;
    std::string         target_name;
    enum {
    enum {
        CdlConflict_UnresolvedBody_Invalid      = 0,
        CdlConflict_UnresolvedBody_Invalid      = 0,
        CdlConflict_UnresolvedBody_Magic        = 0x1b24bb8a
        CdlConflict_UnresolvedBody_Magic        = 0x1b24bb8a
    } cdlconflict_unresolvedbody_cookie;
    } cdlconflict_unresolvedbody_cookie;
    CdlConflict_UnresolvedBody();
    CdlConflict_UnresolvedBody();
    CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
    CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
    CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
    CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// An illegal value can be caused because of a number of properties:
// An illegal value can be caused because of a number of properties:
// legal_values, check_proc, entry_proc, ... In the case of the latter
// legal_values, check_proc, entry_proc, ... In the case of the latter
// the Tcl code should provide text explaining why the value is
// the Tcl code should provide text explaining why the value is
// illegal.
// illegal.
class CdlConflict_IllegalValueBody : public CdlConflictBody {
class CdlConflict_IllegalValueBody : public CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static void         make(CdlTransaction, CdlNode, CdlProperty);
    static void         make(CdlTransaction, CdlNode, CdlProperty);
    bool                resolution_implemented() const;
    bool                resolution_implemented() const;
    std::string         get_explanation() const;
    std::string         get_explanation() const;
    void                set_explanation(std::string);
    void                set_explanation(std::string);
    static bool         test(CdlConflict);
    static bool         test(CdlConflict);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    virtual ~CdlConflict_IllegalValueBody();
    virtual ~CdlConflict_IllegalValueBody();
    bool    inner_resolve(CdlTransaction, int);
    bool    inner_resolve(CdlTransaction, int);
    CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
    CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
    std::string explanation;
    std::string explanation;
    enum {
    enum {
        CdlConflict_IllegalValueBody_Invalid    = 0,
        CdlConflict_IllegalValueBody_Invalid    = 0,
        CdlConflict_IllegalValueBody_Magic      = 0x4fb27ed1
        CdlConflict_IllegalValueBody_Magic      = 0x4fb27ed1
    } cdlconflict_illegalvaluebody_cookie;
    } cdlconflict_illegalvaluebody_cookie;
    CdlConflict_IllegalValueBody();
    CdlConflict_IllegalValueBody();
    CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
    CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
    CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
    CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// There are times when expression evaluation will fail, e.g. because of
// There are times when expression evaluation will fail, e.g. because of
// a division by zero. The explanation is supplied by the evaluation code.
// a division by zero. The explanation is supplied by the evaluation code.
class CdlConflict_EvalExceptionBody : public CdlConflictBody {
class CdlConflict_EvalExceptionBody : public CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string         get_explanation() const;
    std::string         get_explanation() const;
    void                set_explanation(std::string);   // mainly for internal use
    void                set_explanation(std::string);   // mainly for internal use
    static bool         test(CdlConflict);
    static bool         test(CdlConflict);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    virtual ~CdlConflict_EvalExceptionBody();
    virtual ~CdlConflict_EvalExceptionBody();
    CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string explanation;
    std::string explanation;
    enum {
    enum {
        CdlConflict_EvalExceptionBody_Invalid   = 0,
        CdlConflict_EvalExceptionBody_Invalid   = 0,
        CdlConflict_EvalExceptionBody_Magic     = 0x7e64bc41
        CdlConflict_EvalExceptionBody_Magic     = 0x7e64bc41
    } cdlconflict_evalexceptionbody_cookie;
    } cdlconflict_evalexceptionbody_cookie;
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A goal expression evaluates to false. Producing sensible diagnostics
// A goal expression evaluates to false. Producing sensible diagnostics
// depends on a detailed understanding of goal expressions, which will
// depends on a detailed understanding of goal expressions, which will
// have to wait until the inference engine comes along.
// have to wait until the inference engine comes along.
class CdlConflict_RequiresBody : public CdlConflictBody {
class CdlConflict_RequiresBody : public CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static void         make(CdlTransaction, CdlNode, CdlProperty);
    static void         make(CdlTransaction, CdlNode, CdlProperty);
    bool                resolution_implemented() const;
    bool                resolution_implemented() const;
    std::string         get_explanation() const;
    std::string         get_explanation() const;
    static bool         test(CdlConflict);
    static bool         test(CdlConflict);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    virtual ~CdlConflict_RequiresBody();
    virtual ~CdlConflict_RequiresBody();
    bool     inner_resolve(CdlTransaction, int);
    bool     inner_resolve(CdlTransaction, int);
    CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
    CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
    enum {
    enum {
        CdlConflict_RequiresBody_Invalid        = 0,
        CdlConflict_RequiresBody_Invalid        = 0,
        CdlConflict_RequiresBody_Magic          = 0x78436331
        CdlConflict_RequiresBody_Magic          = 0x78436331
    } cdlconflict_requiresbody_cookie;
    } cdlconflict_requiresbody_cookie;
};
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// There is an unusual problem in the configuration data somewhere.
// There is an unusual problem in the configuration data somewhere.
// For example, a parent property can be resolved but the target is
// For example, a parent property can be resolved but the target is
// not a container. There is not a lot that the user can do about
// not a container. There is not a lot that the user can do about
// problems like this, apart from complaining to the component vendor,
// problems like this, apart from complaining to the component vendor,
// but the problem should not be ignored either.
// but the problem should not be ignored either.
class CdlConflict_DataBody : public CdlConflictBody {
class CdlConflict_DataBody : public CdlConflictBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string         get_explanation() const;
    std::string         get_explanation() const;
    static bool         test(CdlConflict);
    static bool         test(CdlConflict);
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    virtual ~CdlConflict_DataBody();
    virtual ~CdlConflict_DataBody();
    CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
    std::string message;
    std::string message;
    enum {
    enum {
        CdlConflict_DataBody_Invalid    = 0,
        CdlConflict_DataBody_Invalid    = 0,
        CdlConflict_DataBody_Magic      = 0x2cec7ad8
        CdlConflict_DataBody_Magic      = 0x2cec7ad8
    } cdlconflict_databody_cookie;
    } cdlconflict_databody_cookie;
};
};
//}}}
//}}}
//{{{  CdlProperty class and derived classes
//{{{  CdlProperty class and derived classes
//{{{  Description
//{{{  Description
// ---------------------------------------------------------------------------
// ---------------------------------------------------------------------------
// There are many different kinds of property. An alias property contains
// There are many different kinds of property. An alias property contains
// a simple string. A check_proc property contains a fragment of Tcl code
// a simple string. A check_proc property contains a fragment of Tcl code
// which can be represented internally as a string, as bytecodes, or both.
// which can be represented internally as a string, as bytecodes, or both.
// A requires property contains a goal expression. ...
// A requires property contains a goal expression. ...
//
//
// The implementation involves a base class CdlProperty and various
// The implementation involves a base class CdlProperty and various
// derived classes such as CdlProperty_StringBody and
// derived classes such as CdlProperty_StringBody and
// CdlProperty_ExpressionBody.
// CdlProperty_ExpressionBody.
//
//
// New CdlProperty objects get created only when reading in CDL scripts,
// New CdlProperty objects get created only when reading in CDL scripts,
// while executing commands like alias and requires. These commands are
// while executing commands like alias and requires. These commands are
// implemented as C++ functions hooked into the TCL interpreter. The
// implemented as C++ functions hooked into the TCL interpreter. The
// property arguments are available as an argc/argv pair. Each command
// property arguments are available as an argc/argv pair. Each command
// will parse and validate the arguments and then invoke an appropriate
// will parse and validate the arguments and then invoke an appropriate
// constructor.
// constructor.
//}}}
//}}}
//{{{  CdlPropertyId_xxx
//{{{  CdlPropertyId_xxx
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Properties are identified by strings rather than by an enum or anything
// Properties are identified by strings rather than by an enum or anything
// like that. A string-based approach allows new properties to be added at
// like that. A string-based approach allows new properties to be added at
// any time without invalidating an existing enum, complicating switch()
// any time without invalidating an existing enum, complicating switch()
// statements, etc. There are some performance issues but these are
// statements, etc. There are some performance issues but these are
// manageable.
// manageable.
//
//
// A disadvantage of using strings is that there is a problem with
// A disadvantage of using strings is that there is a problem with
// typos. Mistyping something like CdlPropertyId_Compile will generally
// typos. Mistyping something like CdlPropertyId_Compile will generally
// result in a compile-time failure. Mistyping "Complie" will cause
// result in a compile-time failure. Mistyping "Complie" will cause
// strange behaviour at run-time and is hard to track down.
// strange behaviour at run-time and is hard to track down.
//
//
// A compromise solution is to have #define'd string constants.
// A compromise solution is to have #define'd string constants.
#define CdlPropertyId_ActiveIf          "ActiveIf"
#define CdlPropertyId_ActiveIf          "ActiveIf"
#define CdlPropertyId_BuildProc         "BuildProc"
#define CdlPropertyId_BuildProc         "BuildProc"
#define CdlPropertyId_Calculated        "Calculated"
#define CdlPropertyId_Calculated        "Calculated"
#define CdlPropertyId_CancelProc        "CancelProc"
#define CdlPropertyId_CancelProc        "CancelProc"
#define CdlPropertyId_CheckProc         "CheckProc"
#define CdlPropertyId_CheckProc         "CheckProc"
#define CdlPropertyId_Compile           "Compile"
#define CdlPropertyId_Compile           "Compile"
#define CdlPropertyId_ConfirmProc       "ConfirmProc"
#define CdlPropertyId_ConfirmProc       "ConfirmProc"
#define CdlPropertyId_DecorationProc    "DecorationProc"
#define CdlPropertyId_DecorationProc    "DecorationProc"
#define CdlPropertyId_DefaultValue      "DefaultValue"
#define CdlPropertyId_DefaultValue      "DefaultValue"
#define CdlPropertyId_Define            "Define"
#define CdlPropertyId_Define            "Define"
#define CdlPropertyId_DefineHeader      "DefineHeader"
#define CdlPropertyId_DefineHeader      "DefineHeader"
#define CdlPropertyId_DefineProc        "DefineProc"
#define CdlPropertyId_DefineProc        "DefineProc"
#define CdlPropertyId_Description       "Description"
#define CdlPropertyId_Description       "Description"
#define CdlPropertyId_Dialog            "Dialog"
#define CdlPropertyId_Dialog            "Dialog"
#define CdlPropertyId_Display           "Display"
#define CdlPropertyId_Display           "Display"
#define CdlPropertyId_DisplayProc       "DisplayProc"
#define CdlPropertyId_DisplayProc       "DisplayProc"
#define CdlPropertyId_Doc               "Doc"
#define CdlPropertyId_Doc               "Doc"
#define CdlPropertyId_EntryProc         "EntryProc"
#define CdlPropertyId_EntryProc         "EntryProc"
#define CdlPropertyId_Flavor            "Flavor"
#define CdlPropertyId_Flavor            "Flavor"
#define CdlPropertyId_DefineFormat      "DefineFormat"
#define CdlPropertyId_DefineFormat      "DefineFormat"
#define CdlPropertyId_Group             "Group"
#define CdlPropertyId_Group             "Group"
#define CdlPropertyId_Hardware          "Hardware"
#define CdlPropertyId_Hardware          "Hardware"
#define CdlPropertyId_IfDefine          "IfDefine"
#define CdlPropertyId_IfDefine          "IfDefine"
#define CdlPropertyId_Implements        "Implements"
#define CdlPropertyId_Implements        "Implements"
#define CdlPropertyId_IncludeDir        "IncludeDir"
#define CdlPropertyId_IncludeDir        "IncludeDir"
#define CdlPropertyId_IncludeFiles      "IncludeFiles"
#define CdlPropertyId_IncludeFiles      "IncludeFiles"
#define CdlPropertyId_InitProc          "InitProc"
#define CdlPropertyId_InitProc          "InitProc"
#define CdlPropertyId_InstallProc       "InstallProc"
#define CdlPropertyId_InstallProc       "InstallProc"
#define CdlPropertyId_LegalValues       "LegalValues"
#define CdlPropertyId_LegalValues       "LegalValues"
#define CdlPropertyId_Library           "Library"
#define CdlPropertyId_Library           "Library"
#define CdlPropertyId_LicenseProc       "LicenseProc"
#define CdlPropertyId_LicenseProc       "LicenseProc"
#define CdlPropertyId_Make              "Make"
#define CdlPropertyId_Make              "Make"
#define CdlPropertyId_Makefile          "Makefile"
#define CdlPropertyId_Makefile          "Makefile"
#define CdlPropertyId_MakeObject        "MakeObject"
#define CdlPropertyId_MakeObject        "MakeObject"
#define CdlPropertyId_NoDefine          "NoDefine"
#define CdlPropertyId_NoDefine          "NoDefine"
#define CdlPropertyId_Object            "Object"
#define CdlPropertyId_Object            "Object"
#define CdlPropertyId_Parent            "Parent"
#define CdlPropertyId_Parent            "Parent"
#define CdlPropertyId_Requires          "Requires"
#define CdlPropertyId_Requires          "Requires"
#define CdlPropertyId_Screen            "Screen"
#define CdlPropertyId_Screen            "Screen"
#define CdlPropertyId_Script            "Script"
#define CdlPropertyId_Script            "Script"
#define CdlPropertyId_UpdateProc        "UpdateProc"
#define CdlPropertyId_UpdateProc        "UpdateProc"
#define CdlPropertyId_Wizard            "Wizard"
#define CdlPropertyId_Wizard            "Wizard"
//}}}
//}}}
//{{{  Base class
//{{{  Base class
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The base class is never used directly. Instead the appropriate derived
// The base class is never used directly. Instead the appropriate derived
// objects are instantiated and when appropriate it will be necessary to
// objects are instantiated and when appropriate it will be necessary to
// do a dynamic cast from a CdlProperty to e.g. a CdlProperty_String.
// do a dynamic cast from a CdlProperty to e.g. a CdlProperty_String.
class CdlPropertyBody {
class CdlPropertyBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    // The destructor is public, to avoid possible problems with STL.
    // The destructor is public, to avoid possible problems with STL.
    virtual ~CdlPropertyBody();
    virtual ~CdlPropertyBody();
    // These routines provide access to the basic data.
    // These routines provide access to the basic data.
    std::string get_property_name() const;
    std::string get_property_name() const;
    // Get hold of the arguments that were present in the original data.
    // Get hold of the arguments that were present in the original data.
    int         get_argc() const;
    int         get_argc() const;
    bool        has_option(std::string) const;
    bool        has_option(std::string) const;
    std::string get_option(std::string) const;
    std::string get_option(std::string) const;
    const std::vector&     get_argv() const;
    const std::vector&     get_argv() const;
    const std::vector >&     get_options() const;
    const std::vector >&     get_options() const;
    // Resolve any references, or generate/update appropriate conflict
    // Resolve any references, or generate/update appropriate conflict
    // objects. The default implementation is a no-op because not all
    // objects. The default implementation is a no-op because not all
    // properties involve references.
    // properties involve references.
    virtual void update(CdlTransaction, CdlNode /* source */, CdlNode /* dest */, CdlUpdate);
    virtual void update(CdlTransaction, CdlNode /* source */, CdlNode /* dest */, CdlUpdate);
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    // The legal constructor can only get invoked from a derived class
    // The legal constructor can only get invoked from a derived class
    // constructor. The first argument identifies the property, e.g.
    // constructor. The first argument identifies the property, e.g.
    // CdlPropertyId_Doc (which is just #define'd to the string
    // CdlPropertyId_Doc (which is just #define'd to the string
    // "doc").
    // "doc").
    //
    //
    // The argc and argv fields provide access to the original
    // The argc and argv fields provide access to the original
    // data in the command that resulted in the property being
    // data in the command that resulted in the property being
    // constructed. Often but not always argv[0] will be the same as
    // constructed. Often but not always argv[0] will be the same as
    // the property id. The argv information is stored mainly for
    // the property id. The argv information is stored mainly for
    // diagnostics purposes, it may be removed in future to avoid
    // diagnostics purposes, it may be removed in future to avoid
    // wasting memory.
    // wasting memory.
    //
    //
    // The options field is the result of parsing options such
    // The options field is the result of parsing options such
    // as -library=libextras.a. It consists of a vector of
    // as -library=libextras.a. It consists of a vector of
    //  pairs, and is usually obtained via
    //  pairs, and is usually obtained via
    // CdlParse::parse_options().
    // CdlParse::parse_options().
    CdlPropertyBody(CdlNode, std::string, int argc, const char* argv[], std::vector >&);
    CdlPropertyBody(CdlNode, std::string, int argc, const char* argv[], std::vector >&);
  private:
  private:
    // This string indicates the command used to define this property,
    // This string indicates the command used to define this property,
    // e.g. "doc" or "define_proc". It is provided to the constructor.
    // e.g. "doc" or "define_proc". It is provided to the constructor.
    std::string                 name;
    std::string                 name;
    // All property data comes out of a file and gets rid via a
    // All property data comes out of a file and gets rid via a
    // Tcl interpreter. The raw file data is stored with the property,
    // Tcl interpreter. The raw file data is stored with the property,
    // mainly for diagnostics purposes.
    // mainly for diagnostics purposes.
    std::vector    argv;
    std::vector    argv;
    std::vector >   options;
    std::vector >   options;
    // The usual set of illegal operations.
    // The usual set of illegal operations.
    CdlPropertyBody();
    CdlPropertyBody();
    CdlPropertyBody(const CdlPropertyBody&);
    CdlPropertyBody(const CdlPropertyBody&);
    CdlPropertyBody& operator=(const CdlPropertyBody&);
    CdlPropertyBody& operator=(const CdlPropertyBody&);
    enum {
    enum {
        CdlPropertyBody_Invalid = 0,
        CdlPropertyBody_Invalid = 0,
        CdlPropertyBody_Magic   = 0x60dd58f4
        CdlPropertyBody_Magic   = 0x60dd58f4
    } cdlpropertybody_cookie;
    } cdlpropertybody_cookie;
};
};
//}}}
//}}}
//{{{  CdlProperty_Minimal
//{{{  CdlProperty_Minimal
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This class is used for properties that are simple flags, e.g. no_define.
// This class is used for properties that are simple flags, e.g. no_define.
// There should be no additional data associated with such properties.
// There should be no additional data associated with such properties.
class CdlProperty_MinimalBody : public CdlPropertyBody {
class CdlProperty_MinimalBody : public CdlPropertyBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_Minimal   make(CdlNode, std::string, int, const char*[], std::vector >&);
    static CdlProperty_Minimal   make(CdlNode, std::string, int, const char*[], std::vector >&);
    virtual ~CdlProperty_MinimalBody( );
    virtual ~CdlProperty_MinimalBody( );
    bool                        check_this( cyg_assert_class_zeal = cyg_quick ) const;
    bool                        check_this( cyg_assert_class_zeal = cyg_quick ) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    typedef CdlPropertyBody     inherited;
    typedef CdlPropertyBody     inherited;
    CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector >&);
    CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector >&);
    enum {
    enum {
        CdlProperty_MinimalBody_Invalid = 0,
        CdlProperty_MinimalBody_Invalid = 0,
        CdlProperty_MinimalBody_Magic   = 0x25625b8c
        CdlProperty_MinimalBody_Magic   = 0x25625b8c
    } cdlproperty_minimalbody_cookie;
    } cdlproperty_minimalbody_cookie;
    CdlProperty_MinimalBody();
    CdlProperty_MinimalBody();
    CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
    CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
    CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
    CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_String
//{{{  CdlProperty_String
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A string property contains a single piece of additional data in the form
// A string property contains a single piece of additional data in the form
// of a string.
// of a string.
class CdlProperty_StringBody : public CdlPropertyBody {
class CdlProperty_StringBody : public CdlPropertyBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_String    make(CdlNode, std::string, std::string, int, const char*[],
    static CdlProperty_String    make(CdlNode, std::string, std::string, int, const char*[],
                                      std::vector >&);
                                      std::vector >&);
    virtual ~CdlProperty_StringBody();
    virtual ~CdlProperty_StringBody();
    std::string                 get_string(void) const;
    std::string                 get_string(void) const;
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    typedef CdlPropertyBody     inherited;
    typedef CdlPropertyBody     inherited;
    CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
    CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
                           std::vector >&);
                           std::vector >&);
    std::string                 data;
    std::string                 data;
    enum {
    enum {
        CdlProperty_StringBody_Invalid = 0,
        CdlProperty_StringBody_Invalid = 0,
        CdlProperty_StringBody_Magic   = 0x78d1ca94
        CdlProperty_StringBody_Magic   = 0x78d1ca94
    } cdlproperty_stringbody_cookie;
    } cdlproperty_stringbody_cookie;
    // The only legal constructor supplies all the data.
    // The only legal constructor supplies all the data.
    CdlProperty_StringBody();
    CdlProperty_StringBody();
    CdlProperty_StringBody(const CdlProperty_StringBody&);
    CdlProperty_StringBody(const CdlProperty_StringBody&);
    CdlProperty_StringBody& operator=(const CdlProperty_StringBody&);
    CdlProperty_StringBody& operator=(const CdlProperty_StringBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_TclCode
//{{{  CdlProperty_TclCode
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A TclCode property is currently equivalent to a string property. In
// A TclCode property is currently equivalent to a string property. In
// future this may change to allow the byte-compiled versions of the
// future this may change to allow the byte-compiled versions of the
// script to be stored.
// script to be stored.
//
//
// One of the properties, "screen" inside a cdl_wizard, also takes
// One of the properties, "screen" inside a cdl_wizard, also takes
// an integer. Rather than create yet another class, this is handled
// an integer. Rather than create yet another class, this is handled
// by a separate constructor.
// by a separate constructor.
class CdlProperty_TclCodeBody : public CdlPropertyBody {
class CdlProperty_TclCodeBody : public CdlPropertyBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_tcl_code, int, const char*[],
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_tcl_code, int, const char*[],
                                      std::vector >&);
                                      std::vector >&);
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
                                      std::vector >&);
                                      std::vector >&);
    virtual ~CdlProperty_TclCodeBody();
    virtual ~CdlProperty_TclCodeBody();
    cdl_int                     get_number(void) const;
    cdl_int                     get_number(void) const;
    const cdl_tcl_code&         get_code(void)   const;
    const cdl_tcl_code&         get_code(void)   const;
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody     inherited;
    typedef CdlPropertyBody     inherited;
    CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
    CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
                            std::vector >&);
                            std::vector >&);
    cdl_int                     number;
    cdl_int                     number;
    cdl_tcl_code                code;
    cdl_tcl_code                code;
    enum {
    enum {
        CdlProperty_TclCodeBody_Invalid = 0,
        CdlProperty_TclCodeBody_Invalid = 0,
        CdlProperty_TclCodeBody_Magic   = 0x7b14d4e5
        CdlProperty_TclCodeBody_Magic   = 0x7b14d4e5
    } cdlproperty_tclcodebody_cookie;
    } cdlproperty_tclcodebody_cookie;
    CdlProperty_TclCodeBody();
    CdlProperty_TclCodeBody();
    CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
    CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
    CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
    CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_StringVector
//{{{  CdlProperty_StringVector
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This is used for multiple constant strings, as opposed to a list
// This is used for multiple constant strings, as opposed to a list
// expression which requires evaluation. One example is a list
// expression which requires evaluation. One example is a list
// of aliases.
// of aliases.
class CdlProperty_StringVectorBody : public CdlPropertyBody {
class CdlProperty_StringVectorBody : public CdlPropertyBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_StringVector     make(CdlNode, std::string, const std::vector&, int, const char*[],
    static CdlProperty_StringVector     make(CdlNode, std::string, const std::vector&, int, const char*[],
                                             std::vector >&);
                                             std::vector >&);
    virtual ~CdlProperty_StringVectorBody();
    virtual ~CdlProperty_StringVectorBody();
    const std::vector&     get_strings() const;
    const std::vector&     get_strings() const;
    std::string                         get_first_string() const;
    std::string                         get_first_string() const;
    unsigned int                        get_number_of_strings() const;
    unsigned int                        get_number_of_strings() const;
    std::string                         get_string(unsigned int) const;
    std::string                         get_string(unsigned int) const;
    bool                                check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
    bool                                check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody            inherited;
    typedef CdlPropertyBody            inherited;
    CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector&, int, const char*[],
    CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector&, int, const char*[],
                                 std::vector >&);
                                 std::vector >&);
    std::vector            data;
    std::vector            data;
    enum {
    enum {
        CdlProperty_StringVectorBody_Invalid = 0,
        CdlProperty_StringVectorBody_Invalid = 0,
        CdlProperty_StringVectorBody_Magic   = 0x4ed039f3
        CdlProperty_StringVectorBody_Magic   = 0x4ed039f3
    } cdlproperty_stringvectorbody_cookie;
    } cdlproperty_stringvectorbody_cookie;
    CdlProperty_StringVectorBody();
    CdlProperty_StringVectorBody();
    CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
    CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
    CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
    CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_Reference
//{{{  CdlProperty_Reference
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This is used for properties such as wizard and dialog, where the data
// This is used for properties such as wizard and dialog, where the data
// identifies some other entity in the system. The class is both a property
// identifies some other entity in the system. The class is both a property
// and a reference object. Most of the desired functionality is provided by
// and a reference object. Most of the desired functionality is provided by
// inheritance from CdlReference.
// inheritance from CdlReference.
class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_Reference make(CdlNode, std::string /* id */, std::string /* destination */,
    static CdlProperty_Reference make(CdlNode, std::string /* id */, std::string /* destination */,
                                      CdlUpdateHandler, int, const char*[],
                                      CdlUpdateHandler, int, const char*[],
                                      std::vector >&);
                                      std::vector >&);
    virtual ~CdlProperty_ReferenceBody();
    virtual ~CdlProperty_ReferenceBody();
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody     inherited_property;
    typedef CdlPropertyBody     inherited_property;
    typedef CdlReference        inherited_reference;
    typedef CdlReference        inherited_reference;
    CdlUpdateHandler            update_handler;
    CdlUpdateHandler            update_handler;
    CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
    CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
                              std::vector >&);
                              std::vector >&);
    enum {
    enum {
        CdlProperty_ReferenceBody_Invalid = 0,
        CdlProperty_ReferenceBody_Invalid = 0,
        CdlProperty_ReferenceBody_Magic   = 0x78100339
        CdlProperty_ReferenceBody_Magic   = 0x78100339
    } cdlproperty_referencebody_cookie;
    } cdlproperty_referencebody_cookie;
    CdlProperty_ReferenceBody();
    CdlProperty_ReferenceBody();
    CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
    CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
    CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
    CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
};
};
//}}}
//}}}
//{{{  CdlProperty_Expression
//{{{  CdlProperty_Expression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// An expression property simply inherits its functionality from the basic
// An expression property simply inherits its functionality from the basic
// property class and from the expression class.
// property class and from the expression class.
class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_Expression       make(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
    static CdlProperty_Expression       make(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
                                             std::vector >&);
                                             std::vector >&);
    virtual ~CdlProperty_ExpressionBody();
    virtual ~CdlProperty_ExpressionBody();
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody     inherited_property;
    typedef CdlPropertyBody     inherited_property;
    typedef CdlExpressionBody   inherited_expression;
    typedef CdlExpressionBody   inherited_expression;
    CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
    CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
                               std::vector >&);
                               std::vector >&);
    CdlUpdateHandler update_handler;
    CdlUpdateHandler update_handler;
    enum {
    enum {
        CdlProperty_ExpressionBody_Invalid = 0,
        CdlProperty_ExpressionBody_Invalid = 0,
        CdlProperty_ExpressionBody_Magic   = 0x05fb4056
        CdlProperty_ExpressionBody_Magic   = 0x05fb4056
    } cdlproperty_expressionbody_cookie;
    } cdlproperty_expressionbody_cookie;
    CdlProperty_ExpressionBody();
    CdlProperty_ExpressionBody();
    CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
    CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
    CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
    CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_ListExpression
//{{{  CdlProperty_ListExpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Similarly a list property simply inherits from property and from
// Similarly a list property simply inherits from property and from
// list expressions.
// list expressions.
class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_ListExpression   make(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
    static CdlProperty_ListExpression   make(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
                                             std::vector >&);
                                             std::vector >&);
    virtual ~CdlProperty_ListExpressionBody();
    virtual ~CdlProperty_ListExpressionBody();
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody         inherited_property;
    typedef CdlPropertyBody         inherited_property;
    typedef CdlListExpressionBody   inherited_expression;
    typedef CdlListExpressionBody   inherited_expression;
    CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
    CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
                                   std::vector >&);
                                   std::vector >&);
    CdlUpdateHandler update_handler;
    CdlUpdateHandler update_handler;
    enum {
    enum {
        CdlProperty_ListExpressionBody_Invalid = 0,
        CdlProperty_ListExpressionBody_Invalid = 0,
        CdlProperty_ListExpressionBody_Magic   = 0x6b0136f5
        CdlProperty_ListExpressionBody_Magic   = 0x6b0136f5
    } cdlproperty_listexpressionbody_cookie;
    } cdlproperty_listexpressionbody_cookie;
    CdlProperty_ListExpressionBody();
    CdlProperty_ListExpressionBody();
    CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
    CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
    CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
    CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
};
};
//}}}
//}}}
//{{{  CdlProperty_GoalExpression
//{{{  CdlProperty_GoalExpression
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// And a goal property inherits from property and from goal expressions.
// And a goal property inherits from property and from goal expressions.
class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    static CdlProperty_GoalExpression   make(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
    static CdlProperty_GoalExpression   make(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
                                             std::vector >&);
                                             std::vector >&);
    virtual ~CdlProperty_GoalExpressionBody();
    virtual ~CdlProperty_GoalExpressionBody();
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    typedef CdlPropertyBody         inherited_property;
    typedef CdlPropertyBody         inherited_property;
    typedef CdlGoalExpressionBody   inherited_expression;
    typedef CdlGoalExpressionBody   inherited_expression;
    CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
    CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
                                   std::vector >&);
                                   std::vector >&);
    CdlUpdateHandler update_handler;
    CdlUpdateHandler update_handler;
    enum {
    enum {
        CdlProperty_GoalExpressionBody_Invalid = 0,
        CdlProperty_GoalExpressionBody_Invalid = 0,
        CdlProperty_GoalExpressionBody_Magic   = 0x08b2b31e
        CdlProperty_GoalExpressionBody_Magic   = 0x08b2b31e
    } cdlproperty_goalexpressionbody_cookie;
    } cdlproperty_goalexpressionbody_cookie;
    CdlProperty_GoalExpressionBody();
    CdlProperty_GoalExpressionBody();
    CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
    CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
    CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
    CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
};
};
//}}}
//}}}
//}}}
//}}}
//{{{  CdlParse class
//{{{  CdlParse class
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// This is another utility class for collecting together parsing-related
// This is another utility class for collecting together parsing-related
// functions.
// functions.
//
//
// Note that this is only a utility class. When libcdl is used for parsing
// Note that this is only a utility class. When libcdl is used for parsing
// things not related to software configuration the new functionality
// things not related to software configuration the new functionality
// does not have to reside inside the CdlParse class, but it may be
// does not have to reside inside the CdlParse class, but it may be
// possible to re-use some of the functionality in that class.
// possible to re-use some of the functionality in that class.
class CdlParse {
class CdlParse {
  public:
  public:
    // Utility routines.
    // Utility routines.
    static std::string  get_tcl_cmd_name(std::string);
    static std::string  get_tcl_cmd_name(std::string);
    static std::string  concatenate_argv(int, const char*[], int);
    static std::string  concatenate_argv(int, const char*[], int);
    static int          parse_options(CdlInterpreter, std::string /* diag_prefix */, char** /* options */,
    static int          parse_options(CdlInterpreter, std::string /* diag_prefix */, char** /* options */,
                                               int /* argc */, const char*[] /* argv */, int /* start_index */,
                                               int /* argc */, const char*[] /* argv */, int /* start_index */,
                                               std::vector >& /* result */);
                                               std::vector >& /* result */);
    static std::string  construct_diagnostic(CdlInterpreter, std::string /* classification */,
    static std::string  construct_diagnostic(CdlInterpreter, std::string /* classification */,
                                             std::string /* sub-identifier */, std::string /* message */);
                                             std::string /* sub-identifier */, std::string /* message */);
    static void         report_error(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
    static void         report_error(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
    static void         report_warning(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
    static void         report_warning(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
    static void         clear_error_count(CdlInterpreter);
    static void         clear_error_count(CdlInterpreter);
    static int          get_error_count(CdlInterpreter);
    static int          get_error_count(CdlInterpreter);
    static void         incr_error_count(CdlInterpreter, int=1);
    static void         incr_error_count(CdlInterpreter, int=1);
    static std::string  get_expression_error_location(void);
    static std::string  get_expression_error_location(void);
    // Support for Tcl's "unknown" command
    // Support for Tcl's "unknown" command
    static int          unknown_command(CdlInterpreter, int, const char*[]);
    static int          unknown_command(CdlInterpreter, int, const char*[]);
    // Property-related utilities
    // Property-related utilities
    static void         report_property_parse_error(CdlInterpreter, std::string, std::string);
    static void         report_property_parse_error(CdlInterpreter, std::string, std::string);
    static void         report_property_parse_error(CdlInterpreter, CdlProperty, std::string);
    static void         report_property_parse_error(CdlInterpreter, CdlProperty, std::string);
    static void         report_property_parse_warning(CdlInterpreter, std::string, std::string);
    static void         report_property_parse_warning(CdlInterpreter, std::string, std::string);
    static void         report_property_parse_warning(CdlInterpreter, CdlProperty, std::string);
    static void         report_property_parse_warning(CdlInterpreter, CdlProperty, std::string);
    // Utility parsing routines
    // Utility parsing routines
    static int  parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
                                       char**, void (*)(CdlInterpreter, CdlProperty_Minimal));
                                       char**, void (*)(CdlInterpreter, CdlProperty_Minimal));
    static int  parse_string_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_string_property(CdlInterpreter, int, const char*[], std::string,
                                      char**, void (*)(CdlInterpreter, CdlProperty_String));
                                      char**, void (*)(CdlInterpreter, CdlProperty_String));
    static int  parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
                                       char**, void (*)(CdlInterpreter, CdlProperty_TclCode));
                                       char**, void (*)(CdlInterpreter, CdlProperty_TclCode));
    static int  parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
                                            char**, void (*)(CdlInterpreter, CdlProperty_StringVector),
                                            char**, void (*)(CdlInterpreter, CdlProperty_StringVector),
                                            bool /* allow_empty */ = false);
                                            bool /* allow_empty */ = false);
    static int  parse_reference_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_reference_property(CdlInterpreter, int, const char*[], std::string,
                                         char**, void (*)(CdlInterpreter, CdlProperty_Reference),
                                         char**, void (*)(CdlInterpreter, CdlProperty_Reference),
                                         bool /* allow_empty */,
                                         bool /* allow_empty */,
                                         CdlUpdateHandler);
                                         CdlUpdateHandler);
    static int  parse_expression_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_expression_property(CdlInterpreter, int, const char*[], std::string,
                                          char **, void (*)(CdlInterpreter, CdlProperty_Expression),
                                          char **, void (*)(CdlInterpreter, CdlProperty_Expression),
                                          CdlUpdateHandler);
                                          CdlUpdateHandler);
    static int  parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
                                              char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
                                              char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
                                              CdlUpdateHandler);
                                              CdlUpdateHandler);
    static int  parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
    static int  parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
                                              char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
                                              char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
                                              CdlUpdateHandler);
                                              CdlUpdateHandler);
};
};
//}}}
//}}}
//{{{  CdlNode
//{{{  CdlNode
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A node object has a name and lives in a hierarchy. Each node keeps
// A node object has a name and lives in a hierarchy. Each node keeps
// track of the toplevel and owner. The memory overheads are
// track of the toplevel and owner. The memory overheads are
// relatively small compared with the performance gains when such
// relatively small compared with the performance gains when such
// information is needed.
// information is needed.
//
//
// A node object also has a vector of properties, and can be referred to
// A node object also has a vector of properties, and can be referred to
// by properties in other nodes. Some of the properties may result in
// by properties in other nodes. Some of the properties may result in
// conflicts.
// conflicts.
class CdlNodeBody {
class CdlNodeBody {
    friend class CdlTest;
    friend class CdlTest;
    // Adding and removing nodes from the hierarchy is done
    // Adding and removing nodes from the hierarchy is done
    // by CdlToplevel members.
    // by CdlToplevel members.
    friend class CdlToplevelBody;
    friend class CdlToplevelBody;
    // CdlLoadable must be able to access the destructor
    // CdlLoadable must be able to access the destructor
    friend class CdlLoadableBody;
    friend class CdlLoadableBody;
    // It is intended that CdlProperties will also add and remove themselves
    // It is intended that CdlProperties will also add and remove themselves
    friend class CdlPropertyBody;
    friend class CdlPropertyBody;
    // CdlReference bind and unbind operations need access to
    // CdlReference bind and unbind operations need access to
    // the referrers vector. So does CdlTransaction::commit()
    // the referrers vector. So does CdlTransaction::commit()
    friend class CdlReference;
    friend class CdlReference;
    friend class CdlTransactionBody;
    friend class CdlTransactionBody;
  public:
  public:
    // Basic information.
    // Basic information.
    std::string         get_name() const;
    std::string         get_name() const;
    CdlContainer        get_parent() const;
    CdlContainer        get_parent() const;
    CdlLoadable         get_owner() const;
    CdlLoadable         get_owner() const;
    CdlToplevel         get_toplevel() const;
    CdlToplevel         get_toplevel() const;
    // Propagation support. Some updates such as active/inactive changes
    // Propagation support. Some updates such as active/inactive changes
    // get applied to nodes as well as to properties. Note that because
    // get applied to nodes as well as to properties. Note that because
    // of multiple inheritance this virtual call can get confusing.
    // of multiple inheritance this virtual call can get confusing.
    virtual void        update(CdlTransaction, CdlUpdate);
    virtual void        update(CdlTransaction, CdlUpdate);
    // Is this node active or not? The is_active() call refers
    // Is this node active or not? The is_active() call refers
    // to the global state, things may be different inside a
    // to the global state, things may be different inside a
    // transaction.
    // transaction.
    bool                is_active() const;
    bool                is_active() const;
    bool                is_active(CdlTransaction transaction);
    bool                is_active(CdlTransaction transaction);
    // Generally nodes become active when the parent becomes
    // Generally nodes become active when the parent becomes
    // active and enabled. Some derived classes may impose
    // active and enabled. Some derived classes may impose
    // additional restrictions, for example because of
    // additional restrictions, for example because of
    // active_if constraints. This routine can be used
    // active_if constraints. This routine can be used
    // to check whether or not a node should become active.
    // to check whether or not a node should become active.
    virtual bool        test_active(CdlTransaction);
    virtual bool        test_active(CdlTransaction);
    // Provide access to the various properties. Currently all this
    // Provide access to the various properties. Currently all this
    // information is publicly available.
    // information is publicly available.
    const std::vector&     get_properties() const;
    const std::vector&     get_properties() const;
    CdlProperty                         get_property(std::string) const;
    CdlProperty                         get_property(std::string) const;
    void                                get_properties(std::string, std::vector&) const;
    void                                get_properties(std::string, std::vector&) const;
    std::vector            get_properties(std::string) const;
    std::vector            get_properties(std::string) const;
    bool                                has_property(std::string) const;
    bool                                has_property(std::string) const;
    int                                 count_properties(std::string) const;
    int                                 count_properties(std::string) const;
    // Provide access to the various global conflicts. More
    // Provide access to the various global conflicts. More
    // commonly conflicts are accessed on a per-transaction basis.
    // commonly conflicts are accessed on a per-transaction basis.
    void get_conflicts(std::vector&) const;
    void get_conflicts(std::vector&) const;
    void get_conflicts(bool (*)(CdlConflict), std::vector&) const;
    void get_conflicts(bool (*)(CdlConflict), std::vector&) const;
    void get_structural_conflicts(std::vector&) const;
    void get_structural_conflicts(std::vector&) const;
    void get_structural_conflicts(bool (*)(CdlConflict), std::vector&) const;
    void get_structural_conflicts(bool (*)(CdlConflict), std::vector&) const;
    // Provide access to all the referrers. This may not get used very
    // Provide access to all the referrers. This may not get used very
    // much outside the library itself.
    // much outside the library itself.
    const std::vector&     get_referrers() const;
    const std::vector&     get_referrers() const;
    // Add property parsers and validation code appropriate for a
    // Add property parsers and validation code appropriate for a
    // node. Currently this is a no-op, there are no properties
    // node. Currently this is a no-op, there are no properties
    // associated with every node, but this may change in future e.g.
    // associated with every node, but this may change in future e.g.
    // for diagnostics purposes.
    // for diagnostics purposes.
    static void add_property_parsers(std::vector& parsers);
    static void add_property_parsers(std::vector& parsers);
    void        check_properties(CdlInterpreter);
    void        check_properties(CdlInterpreter);
    // Persistence support. The final classes such as cdl_option
    // Persistence support. The final classes such as cdl_option
    // should provide implementations of these functions. The
    // should provide implementations of these functions. The
    // base function takes care of data that was present in an
    // base function takes care of data that was present in an
    // original save file but which was not recognised.
    // original save file but which was not recognised.
    //
    //
    // Configuration save files are Tcl scripts, so it seems
    // Configuration save files are Tcl scripts, so it seems
    // appropriate to handle the I/O via the Tcl library and
    // appropriate to handle the I/O via the Tcl library and
    // to have a TCL interpreter available.
    // to have a TCL interpreter available.
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    bool has_additional_savefile_information() const;
    bool has_additional_savefile_information() const;
    // Mainly for diagnostics code, what is the actual name for this
    // Mainly for diagnostics code, what is the actual name for this
    // type of CDL object? This should be in terms of CDL data, e.g.
    // type of CDL object? This should be in terms of CDL data, e.g.
    // "package" or "component", rather than in implementation terms
    // "package" or "component", rather than in implementation terms
    // such as "CdlPackageBody".
    // such as "CdlPackageBody".
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    // CdlNodeBodies are only instantiated by derived classes.
    // CdlNodeBodies are only instantiated by derived classes.
    // They must always have a name. They need not be placed
    // They must always have a name. They need not be placed
    // in the hierarchy immediately, that can wait until
    // in the hierarchy immediately, that can wait until
    // later.
    // later.
    CdlNodeBody(std::string);
    CdlNodeBody(std::string);
    // A dummy constructor is needed because of the virtual
    // A dummy constructor is needed because of the virtual
    // inheritance.
    // inheritance.
    CdlNodeBody();
    CdlNodeBody();
    // Nodes cannot be destroyed directly by application code,
    // Nodes cannot be destroyed directly by application code,
    // only by higher-level library functions such as unload_package()
    // only by higher-level library functions such as unload_package()
    virtual ~CdlNodeBody();
    virtual ~CdlNodeBody();
    // Updating the name is rarely required, but is useful for savefiles.
    // Updating the name is rarely required, but is useful for savefiles.
    void                set_name(std::string);
    void                set_name(std::string);
    // Is the node currently active? This applies to the global state
    // Is the node currently active? This applies to the global state
    // only, not per-transaction state. Some derived classes may want
    // only, not per-transaction state. Some derived classes may want
    // to override the default value
    // to override the default value
    bool                active;
    bool                active;
  private:
  private:
    // The basic data. The name is known during construction.
    // The basic data. The name is known during construction.
    // The other three fields get updated by e.g. CdlToplevel::add_node();
    // The other three fields get updated by e.g. CdlToplevel::add_node();
    std::string         name;
    std::string         name;
    CdlContainer        parent;
    CdlContainer        parent;
    CdlLoadable         owner;
    CdlLoadable         owner;
    CdlToplevel         toplevel;
    CdlToplevel         toplevel;
    // This is used by remove_node_from_toplevel()/add_node_to_toplevel()
    // This is used by remove_node_from_toplevel()/add_node_to_toplevel()
    // to allow the latter to exactly reverse the former
    // to allow the latter to exactly reverse the former
    int                 remove_node_container_position;
    int                 remove_node_container_position;
    // Properties normally only get added during the parsing process,
    // Properties normally only get added during the parsing process,
    // and only get removed when the object itself is destroyed.
    // and only get removed when the object itself is destroyed.
    // A vector is the obvious implementation.
    // A vector is the obvious implementation.
    std::vector properties;
    std::vector properties;
    // Currently a vector of referrers is used. This vector is subject
    // Currently a vector of referrers is used. This vector is subject
    // to change when packages get loaded and unloaded, possibly a
    // to change when packages get loaded and unloaded, possibly a
    // list would be better.
    // list would be better.
    std::vector referrers;
    std::vector referrers;
    // Savefiles may contain information that is not recognised by the
    // Savefiles may contain information that is not recognised by the
    // current library, especially because of savefile hooks which
    // current library, especially because of savefile hooks which
    // allow e.g. the configuration tool to store its own information
    // allow e.g. the configuration tool to store its own information
    // in save files. This information must not be lost, even if you are
    // in save files. This information must not be lost, even if you are
    // e.g. mixing command line and GUI tools. This vector holds
    // e.g. mixing command line and GUI tools. This vector holds
    // the savefile information so that it can be put in the next
    // the savefile information so that it can be put in the next
    // savefile.
    // savefile.
    std::vector unsupported_savefile_strings;
    std::vector unsupported_savefile_strings;
    enum {
    enum {
        CdlNodeBody_Invalid     = 0,
        CdlNodeBody_Invalid     = 0,
        CdlNodeBody_Magic       = 0x309595b5
        CdlNodeBody_Magic       = 0x309595b5
    } cdlnodebody_cookie;
    } cdlnodebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlNodeBody(const CdlNodeBody&);
    CdlNodeBody(const CdlNodeBody&);
    CdlNodeBody& operator=(const CdlNodeBody&);
    CdlNodeBody& operator=(const CdlNodeBody&);
};
};
//}}}
//}}}
//{{{  CdlContainer
//{{{  CdlContainer
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A container is a node that can contain other nodes.
// A container is a node that can contain other nodes.
class CdlContainerBody : virtual public CdlNodeBody {
class CdlContainerBody : virtual public CdlNodeBody {
    friend class Cdltest;
    friend class Cdltest;
    // Allow CdlNode::check_this() access to the internals
    // Allow CdlNode::check_this() access to the internals
    friend class CdlNodeBody;
    friend class CdlNodeBody;
    // Adding a node to the hierarchy is done by a CdlToplevel member.
    // Adding a node to the hierarchy is done by a CdlToplevel member.
    // Ditto for removing.
    // Ditto for removing.
    friend class CdlToplevelBody;
    friend class CdlToplevelBody;
    // Deleting a container can happen inside CdlToplevel and CdlLoadable
    // Deleting a container can happen inside CdlToplevel and CdlLoadable
    friend class CdlLoadableBody;
    friend class CdlLoadableBody;
  public:
  public:
    const std::vector& get_contents() const;
    const std::vector& get_contents() const;
    bool                        contains(CdlConstNode, bool /* recurse */ = false) const;
    bool                        contains(CdlConstNode, bool /* recurse */ = false) const;
    bool                        contains(const std::string, bool /* recurse */ = false) const;
    bool                        contains(const std::string, bool /* recurse */ = false) const;
    CdlNode                     find_node(const std::string, bool /* recurse */ = false) const;
    CdlNode                     find_node(const std::string, bool /* recurse */ = false) const;
    // Propagation support. Some updates such as active/inactive changes
    // Propagation support. Some updates such as active/inactive changes
    // get applied to nodes as well as to properties.
    // get applied to nodes as well as to properties.
    virtual void update(CdlTransaction, CdlUpdate);
    virtual void update(CdlTransaction, CdlUpdate);
    // Persistence support.
    // Persistence support.
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    // Containers cannot be destroyed explicitly, only via higher-level
    // Containers cannot be destroyed explicitly, only via higher-level
    // code such as unload_package();
    // code such as unload_package();
    virtual ~CdlContainerBody();
    virtual ~CdlContainerBody();
    CdlContainerBody();
    CdlContainerBody();
    // Special constructor needed for internal use.
    // Special constructor needed for internal use.
    CdlContainerBody(std::string);
    CdlContainerBody(std::string);
    // The CdlToplevel class needs access to its own contents.
    // The CdlToplevel class needs access to its own contents.
    std::vector                contents;
    std::vector                contents;
  private:
  private:
    enum {
    enum {
        CdlContainerBody_Invalid        = 0,
        CdlContainerBody_Invalid        = 0,
        CdlContainerBody_Magic          = 0x543c5f1d
        CdlContainerBody_Magic          = 0x543c5f1d
    } cdlcontainerbody_cookie;
    } cdlcontainerbody_cookie;
    // Illegal operations
    // Illegal operations
    CdlContainerBody(const CdlContainerBody&);
    CdlContainerBody(const CdlContainerBody&);
    CdlContainerBody& operator=(const CdlContainerBody&);
    CdlContainerBody& operator=(const CdlContainerBody&);
};
};
//}}}
//}}}
//{{{  CdlLoadable
//{{{  CdlLoadable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A loadable object is a container that gets loaded or unloaded
// A loadable object is a container that gets loaded or unloaded
// atomically from a toplevel. The key difference is that a loadable
// atomically from a toplevel. The key difference is that a loadable
// keeps track of all nodes that were loaded as part of this
// keeps track of all nodes that were loaded as part of this
// operation, thus allowing unload operations to happen safely even if
// operation, thus allowing unload operations to happen safely even if
// nodes get re-parented all over the hierarchy. In addition, there is
// nodes get re-parented all over the hierarchy. In addition, there is
// a slave interpreter associated with every loadable.
// a slave interpreter associated with every loadable.
class CdlLoadableBody : virtual public CdlContainerBody {
class CdlLoadableBody : virtual public CdlContainerBody {
    friend class CdlTest;
    friend class CdlTest;
    // Allow CdlNode::check_this() access to the internals
    // Allow CdlNode::check_this() access to the internals
    friend class CdlNodeBody;
    friend class CdlNodeBody;
    // Adding nodes to the hierarchy is done by a toplevel member
    // Adding nodes to the hierarchy is done by a toplevel member
    friend class CdlToplevelBody;
    friend class CdlToplevelBody;
  public:
  public:
    virtual ~CdlLoadableBody();
    virtual ~CdlLoadableBody();
    const std::vector&         get_owned() const;
    const std::vector&         get_owned() const;
    bool                                owns(CdlConstNode) const;
    bool                                owns(CdlConstNode) const;
    CdlInterpreter                      get_interpreter() const;
    CdlInterpreter                      get_interpreter() const;
    std::string                         get_directory() const;
    std::string                         get_directory() const;
    // Some properties such as doc and compile reference filenames.
    // Some properties such as doc and compile reference filenames.
    // A search facility is useful.
    // A search facility is useful.
    virtual std::string find_relative_file(std::string /* filename */, std::string /* directory */ = "") const;
    virtual std::string find_relative_file(std::string /* filename */, std::string /* directory */ = "") const;
    virtual std::string find_absolute_file(std::string, std::string, bool /* allow_urls */ = false) const;
    virtual std::string find_absolute_file(std::string, std::string, bool /* allow_urls */ = false) const;
    virtual bool        has_subdirectory(std::string) const;
    virtual bool        has_subdirectory(std::string) const;
    // These support load/unload operations inside transactions
    // These support load/unload operations inside transactions
    // They are static members because some of them will want
    // They are static members because some of them will want
    // to delete the loadable.
    // to delete the loadable.
    static void         transaction_commit_load(CdlTransaction, CdlLoadable);
    static void         transaction_commit_load(CdlTransaction, CdlLoadable);
    static void         transaction_cancel_load(CdlTransaction, CdlLoadable);
    static void         transaction_cancel_load(CdlTransaction, CdlLoadable);
    static void         transaction_commit_unload(CdlTransaction, CdlLoadable);
    static void         transaction_commit_unload(CdlTransaction, CdlLoadable);
    static void         transaction_cancel_unload(CdlTransaction, CdlLoadable);
    static void         transaction_cancel_unload(CdlTransaction, CdlLoadable);
    // Binding and unbinding of properties. This involves processing
    // Binding and unbinding of properties. This involves processing
    // the various properties, calculating default values, etc.
    // the various properties, calculating default values, etc.
    void                bind(CdlTransaction);
    void                bind(CdlTransaction);
    void                unbind(CdlTransaction);
    void                unbind(CdlTransaction);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlLoadableBody(CdlToplevel, std::string /* directory */);
    CdlLoadableBody(CdlToplevel, std::string /* directory */);
    // Needed by derived classes, but not actually used.
    // Needed by derived classes, but not actually used.
    CdlLoadableBody();
    CdlLoadableBody();
  private:
  private:
    std::vector owned;
    std::vector owned;
    CdlInterpreter       interp;
    CdlInterpreter       interp;
    std::string          directory;
    std::string          directory;
    // Used by add/remove_node_from_toplevel()
    // Used by add/remove_node_from_toplevel()
    int                  remove_node_loadables_position;
    int                  remove_node_loadables_position;
    enum {
    enum {
        CdlLoadableBody_Invalid = 0,
        CdlLoadableBody_Invalid = 0,
        CdlLoadableBody_Magic   = 0x488d6127
        CdlLoadableBody_Magic   = 0x488d6127
    } cdlloadablebody_cookie;
    } cdlloadablebody_cookie;
    // Invalid operations
    // Invalid operations
    CdlLoadableBody(const CdlLoadableBody&);
    CdlLoadableBody(const CdlLoadableBody&);
    CdlLoadableBody& operator=(const CdlLoadableBody&);
    CdlLoadableBody& operator=(const CdlLoadableBody&);
};
};
//}}}
//}}}
//{{{  CdlToplevel
//{{{  CdlToplevel
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Toplevels are containers that live at the top of a hierarchy
// Toplevels are containers that live at the top of a hierarchy
// (surprise surprise). This means that they do not have a parent.
// (surprise surprise). This means that they do not have a parent.
// In addition a toplevel object keeps track of all the names
// In addition a toplevel object keeps track of all the names
// used, guaranteeing uniqueness and providing a quick lookup
// used, guaranteeing uniqueness and providing a quick lookup
// facility.
// facility.
//
//
// Every container is also a node, so every toplevel is a node.
// Every container is also a node, so every toplevel is a node.
// Inheritance from CdlNode may seem wrong. However it achieves
// Inheritance from CdlNode may seem wrong. However it achieves
// consistency, everything in the hierarchy including the toplevel
// consistency, everything in the hierarchy including the toplevel
// is a node. The main disadvantage is that every toplevel now
// is a node. The main disadvantage is that every toplevel now
// needs a name.
// needs a name.
class CdlToplevelBody : virtual public CdlContainerBody {
class CdlToplevelBody : virtual public CdlContainerBody {
    friend class CdlTest;
    friend class CdlTest;
    // Allow CdlNode::check_this() access to the internals
    // Allow CdlNode::check_this() access to the internals
    friend class CdlNodeBody;
    friend class CdlNodeBody;
    // The CdlTransaction class needs direct access to the lists
    // The CdlTransaction class needs direct access to the lists
    // of conflicts.
    // of conflicts.
    friend class CdlTransactionBody;
    friend class CdlTransactionBody;
  public:
  public:
    virtual ~CdlToplevelBody();
    virtual ~CdlToplevelBody();
    // Updating the hierarchy. This happens a node at a time. Adding a
    // Updating the hierarchy. This happens a node at a time. Adding a
    // node involves updating the name->node map in the toplevel,
    // node involves updating the name->node map in the toplevel,
    // setting the node's parent/owner/toplevel fields, and updating
    // setting the node's parent/owner/toplevel fields, and updating
    // the parent and owner containers. The owner may be 0 for special
    // the parent and owner containers. The owner may be 0 for special
    // nodes such as the orphans container. The parent must be known,
    // nodes such as the orphans container. The parent must be known,
    // although it may change later on during a change_parent() call.
    // although it may change later on during a change_parent() call.
    //
    //
    // Removing a node is more complicated, and involves a two-stage
    // Removing a node is more complicated, and involves a two-stage
    // process. First the node is removed from the toplevel, thus
    // process. First the node is removed from the toplevel, thus
    // eliminating the name->node mapping. The owner and parent fields
    // eliminating the name->node mapping. The owner and parent fields
    // are preserved at this stage (except for the loadable itself),
    // are preserved at this stage (except for the loadable itself),
    // and the operation may be undone if the relevant transaction
    // and the operation may be undone if the relevant transaction
    // gets cancelled. If the transaction gets committed then the
    // gets cancelled. If the transaction gets committed then the
    // second remove operation handles the owner and parent fields,
    // second remove operation handles the owner and parent fields,
    // just prior to the node being deleted. For convenience there
    // just prior to the node being deleted. For convenience there
    // are also per-loadable variants for some of these.
    // are also per-loadable variants for some of these.
    //
    //
    // change_parent() is used to support parent-properties.
    // change_parent() is used to support parent-properties.
    // A container of 0 indicates an orphan, i.e. a parent
    // A container of 0 indicates an orphan, i.e. a parent
    // property that did not or does not correspond to a
    // property that did not or does not correspond to a
    // current container.
    // current container.
    //
    //
    // There is also a clean-up call. This gets used for interfaces
    // There is also a clean-up call. This gets used for interfaces
    // which may alternate between belonging to a loadable and
    // which may alternate between belonging to a loadable and
    // being auto-created.
    // being auto-created.
    void add_node(CdlLoadable, CdlContainer, CdlNode);
    void add_node(CdlLoadable, CdlContainer, CdlNode);
    void add_node_to_toplevel(CdlNode);
    void add_node_to_toplevel(CdlNode);
    void remove_node_from_toplevel(CdlNode);
    void remove_node_from_toplevel(CdlNode);
    static void remove_node(CdlLoadable, CdlContainer, CdlNode);
    static void remove_node(CdlLoadable, CdlContainer, CdlNode);
    void add_loadable_to_toplevel(CdlLoadable);
    void add_loadable_to_toplevel(CdlLoadable);
    void remove_loadable_from_toplevel(CdlLoadable);
    void remove_loadable_from_toplevel(CdlLoadable);
    void change_parent(CdlLoadable, CdlContainer /* current */, CdlContainer /* new */, CdlNode, int /* pos */ = -1);
    void change_parent(CdlLoadable, CdlContainer /* current */, CdlContainer /* new */, CdlNode, int /* pos */ = -1);
    void cleanup_orphans();
    void cleanup_orphans();
    // Toplevels keep track of all the loadables, in addition to
    // Toplevels keep track of all the loadables, in addition to
    // inheriting tree behaviour from CdlContainer. This is convenient
    // inheriting tree behaviour from CdlContainer. This is convenient
    // for some operations like determining build information
    // for some operations like determining build information
    // which must operate on a per-loadable basis.
    // which must operate on a per-loadable basis.
    const std::vector& get_loadables() const;
    const std::vector& get_loadables() const;
    // Name uniqueness is guaranteed. It is convenient to have an STL
    // Name uniqueness is guaranteed. It is convenient to have an STL
    // map as a lookup service.
    // map as a lookup service.
    CdlNode lookup(const std::string) const;
    CdlNode lookup(const std::string) const;
    // There are two conflict lists associated with each toplevel. One
    // There are two conflict lists associated with each toplevel. One
    // is for "structural" conflicts, ones that can only be resolved
    // is for "structural" conflicts, ones that can only be resolved
    // by a fairly major change such as loading another package: a
    // by a fairly major change such as loading another package: a
    // typical example is an unresolved parent reference. The other is
    // typical example is an unresolved parent reference. The other is
    // for conflicts that can probably be resolved simply by changing
    // for conflicts that can probably be resolved simply by changing
    // some values. Both sets of conflicts are held as a simple list.
    // some values. Both sets of conflicts are held as a simple list.
    //
    //
    // The active vs. inactive state of a CDL entity affects the
    // The active vs. inactive state of a CDL entity affects the
    // location of structural vs. non-structural conflicts. If an
    // location of structural vs. non-structural conflicts. If an
    // entity becomes inactive then structural conflicts are not
    // entity becomes inactive then structural conflicts are not
    // affected, but non-structural conflicts are removed from the
    // affected, but non-structural conflicts are removed from the
    // global list. If an entity's "requires" expression is not
    // global list. If an entity's "requires" expression is not
    // satisfied but the entity is inactive anyway then this is
    // satisfied but the entity is inactive anyway then this is
    // harmless.
    // harmless.
    const std::list& get_all_conflicts() const;
    const std::list& get_all_conflicts() const;
    const std::list& get_all_structural_conflicts() const;
    const std::list& get_all_structural_conflicts() const;
    // Try to resolve some or all conflicts. Typically a new transaction
    // Try to resolve some or all conflicts. Typically a new transaction
    // will be created for this.
    // will be created for this.
    void        resolve_conflicts(const std::vector&);
    void        resolve_conflicts(const std::vector&);
    void        resolve_all_conflicts();
    void        resolve_all_conflicts();
    // Toplevels can have descriptions provided by the user. This is
    // Toplevels can have descriptions provided by the user. This is
    // particularly important for pre-defined templates, target
    // particularly important for pre-defined templates, target
    // board descriptions, etc. where the user would like some
    // board descriptions, etc. where the user would like some
    // extra information about the template before loading it in.
    // extra information about the template before loading it in.
    // The default value is an empty string.
    // The default value is an empty string.
    std::string         get_description() const;
    std::string         get_description() const;
    void                set_description(std::string);
    void                set_description(std::string);
    // Each toplevel must have an associated master Tcl interpreter.
    // Each toplevel must have an associated master Tcl interpreter.
    CdlInterpreter      get_interpreter() const;
    CdlInterpreter      get_interpreter() const;
    // Each toplevel should also have an associated directory for
    // Each toplevel should also have an associated directory for
    // the component repository. It is not required that all loadables
    // the component repository. It is not required that all loadables
    // are relative to this, but that is the default behaviour.
    // are relative to this, but that is the default behaviour.
    std::string         get_directory() const;
    std::string         get_directory() const;
    // Each toplevel may have a single active main transaction.
    // Each toplevel may have a single active main transaction.
    // For now there is no support for concurrent transactions
    // For now there is no support for concurrent transactions
    // operating on a single toplevel (although nested transactions
    // operating on a single toplevel (although nested transactions
    // are allowed)
    // are allowed)
    CdlTransaction      get_active_transaction() const;
    CdlTransaction      get_active_transaction() const;
    // Build and define operations are available for all toplevels,
    // Build and define operations are available for all toplevels,
    // even if they are not always applicable
    // even if they are not always applicable
    void                get_build_info(CdlBuildInfo&);
    void                get_build_info(CdlBuildInfo&);
    void                get_all_build_info(CdlBuildInfo&);
    void                get_all_build_info(CdlBuildInfo&);
    void                generate_config_headers(std::string);
    void                generate_config_headers(std::string);
    void                get_config_headers(std::vector&);
    void                get_config_headers(std::vector&);
    void                generate_build_tree(std::string, std::string = "");
    void                generate_build_tree(std::string, std::string = "");
    // Values can be stored in limbo. This is useful when unloading
    // Values can be stored in limbo. This is useful when unloading
    // and reloading packages, e.g. when changing a version the
    // and reloading packages, e.g. when changing a version the
    // current settings can be preserved as much as possible.
    // current settings can be preserved as much as possible.
    void                set_limbo_value(CdlValuable);
    void                set_limbo_value(CdlValuable);
    bool                has_limbo_value(std::string) const;
    bool                has_limbo_value(std::string) const;
    CdlValue            get_limbo_value(std::string) const;
    CdlValue            get_limbo_value(std::string) const;
    CdlValue            get_and_remove_limbo_value(std::string);
    CdlValue            get_and_remove_limbo_value(std::string);
    void                clear_limbo();
    void                clear_limbo();
    // Persistence support. These are commented in the source code.
    // Persistence support. These are commented in the source code.
           void         initialize_savefile_support();
           void         initialize_savefile_support();
    static bool         savefile_support_initialized();
    static bool         savefile_support_initialized();
           void         add_savefile_command(std::string, CdlSaveCallback, CdlInterpreterCommand);
           void         add_savefile_command(std::string, CdlSaveCallback, CdlInterpreterCommand);
           void         add_savefile_subcommand(std::string, std::string, CdlSaveCallback, CdlInterpreterCommand);
           void         add_savefile_subcommand(std::string, std::string, CdlSaveCallback, CdlInterpreterCommand);
           void         get_savefile_commands(std::vector&);
           void         get_savefile_commands(std::vector&);
           void         get_savefile_subcommands(std::string, std::vector&);
           void         get_savefile_subcommands(std::string, std::vector&);
           void         save_command_details(CdlInterpreter, Tcl_Channel, int, bool);
           void         save_command_details(CdlInterpreter, Tcl_Channel, int, bool);
    static int          savefile_handle_command(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_command(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_unsupported(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_unsupported(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_unknown(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_unknown(CdlInterpreter, int, const char*[]);
           void         save_unsupported_commands(CdlInterpreter, Tcl_Channel, int, bool);
           void         save_unsupported_commands(CdlInterpreter, Tcl_Channel, int, bool);
    static cdl_int      get_library_savefile_version();
    static cdl_int      get_library_savefile_version();
    static int          savefile_handle_version(CdlInterpreter, int, const char*[]);
    static int          savefile_handle_version(CdlInterpreter, int, const char*[]);
    static cdl_int      get_savefile_version(CdlInterpreter);
    static cdl_int      get_savefile_version(CdlInterpreter);
           void         save_conflicts(CdlInterpreter, Tcl_Channel, int, bool);
           void         save_conflicts(CdlInterpreter, Tcl_Channel, int, bool);
    static void         save_separator(CdlInterpreter, Tcl_Channel, std::string, bool);
    static void         save_separator(CdlInterpreter, Tcl_Channel, std::string, bool);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlToplevelBody(CdlInterpreter, std::string);
    CdlToplevelBody(CdlInterpreter, std::string);
  private:
  private:
    std::map       lookup_table;
    std::map       lookup_table;
    std::vector            loadables;
    std::vector            loadables;
    std::map      limbo;
    std::map      limbo;
    CdlInterpreter                      interp;
    CdlInterpreter                      interp;
    CdlContainer                        orphans;
    CdlContainer                        orphans;
    std::string                         description;
    std::string                         description;
    std::string                         directory;
    std::string                         directory;
    std::list              conflicts;
    std::list              conflicts;
    std::list              structural_conflicts;
    std::list              structural_conflicts;
    // The savefile support corresponding to this application.
    // The savefile support corresponding to this application.
    static cdl_int savefile_version;
    static cdl_int savefile_version;
    static bool    savefile_commands_initialized;
    static bool    savefile_commands_initialized;
    static std::vector savefile_commands;
    static std::vector savefile_commands;
    static std::map > savefile_subcommands;
    static std::map > savefile_subcommands;
    // Per-toplevel support. A savefile may contain unrecognised
    // Per-toplevel support. A savefile may contain unrecognised
    // commands at the toplevel of a file, as well as unrecognised
    // commands at the toplevel of a file, as well as unrecognised
    // commands in e.g. the body of a cdl_configuration command.
    // commands in e.g. the body of a cdl_configuration command.
    // The latter is handled via the CdlNode base class.
    // The latter is handled via the CdlNode base class.
    std::vector unsupported_savefile_toplevel_strings;
    std::vector unsupported_savefile_toplevel_strings;
    std::vector unsupported_savefile_commands;
    std::vector unsupported_savefile_commands;
    std::map > unsupported_savefile_subcommands;
    std::map > unsupported_savefile_subcommands;
    // Keep track of the current active transaction for this toplevel (if any)
    // Keep track of the current active transaction for this toplevel (if any)
    CdlTransaction      transaction;
    CdlTransaction      transaction;
    enum {
    enum {
        CdlToplevelBody_Invalid = 0,
        CdlToplevelBody_Invalid = 0,
        CdlToplevelBody_Magic   = 0x0834666e
        CdlToplevelBody_Magic   = 0x0834666e
    } cdltoplevelbody_cookie;
    } cdltoplevelbody_cookie;
    // Invalid operations
    // Invalid operations
    CdlToplevelBody(const CdlToplevelBody&);
    CdlToplevelBody(const CdlToplevelBody&);
    CdlToplevelBody& operator=(const CdlToplevelBody&);
    CdlToplevelBody& operator=(const CdlToplevelBody&);
};
};
//}}}
//}}}
//{{{  CdlUserVisible
//{{{  CdlUserVisible
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A user-visible object is likely to have properties such as display,
// A user-visible object is likely to have properties such as display,
// description and doc. Many user-visible objects will have values but
// description and doc. Many user-visible objects will have values but
// not all, for example custom dialogs are likely to have a doc
// not all, for example custom dialogs are likely to have a doc
// property but they do not have a value.
// property but they do not have a value.
class CdlUserVisibleBody : virtual public CdlNodeBody {
class CdlUserVisibleBody : virtual public CdlNodeBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlUserVisibleBody();
    virtual ~CdlUserVisibleBody();
    std::string         get_display() const;
    std::string         get_display() const;
    std::string         get_description() const;
    std::string         get_description() const;
    std::string         get_doc() const;
    std::string         get_doc() const;
    // NOTE: this will only work for absolute doc strings or for doc
    // NOTE: this will only work for absolute doc strings or for doc
    // strings that are relative to the package.
    // strings that are relative to the package.
    std::string         get_doc_url() const;
    std::string         get_doc_url() const;
    // Add property parsers and validation code appropriate for a
    // Add property parsers and validation code appropriate for a
    // user-visible object such as doc and description
    // user-visible object such as doc and description
    static void         add_property_parsers(std::vector& parsers);
    static void         add_property_parsers(std::vector& parsers);
    void                check_properties(CdlInterpreter);
    void                check_properties(CdlInterpreter);
    static int          parse_description(CdlInterpreter, int, const char*[]);
    static int          parse_description(CdlInterpreter, int, const char*[]);
    static int          parse_display(CdlInterpreter, int, const char*[]);
    static int          parse_display(CdlInterpreter, int, const char*[]);
    static int          parse_doc(CdlInterpreter, int, const char*[]);
    static int          parse_doc(CdlInterpreter, int, const char*[]);
    // Persistence support. The save code simply outputs some comments
    // Persistence support. The save code simply outputs some comments
    // corresponding to the display, doc and description properties.
    // corresponding to the display, doc and description properties.
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlUserVisibleBody();
    CdlUserVisibleBody();
  private:
  private:
    enum {
    enum {
        CdlUserVisibleBody_Invalid      = 0,
        CdlUserVisibleBody_Invalid      = 0,
        CdlUserVisibleBody_Magic        = 0x13bbc817
        CdlUserVisibleBody_Magic        = 0x13bbc817
    } cdluservisiblebody_cookie;
    } cdluservisiblebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlUserVisibleBody(const CdlUserVisibleBody&);
    CdlUserVisibleBody(const CdlUserVisibleBody&);
    CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
    CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
};
};
//}}}
//}}}
//{{{  CdlParentable
//{{{  CdlParentable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A parentable object may have the parent property, redefining its
// A parentable object may have the parent property, redefining its
// position in the hierarchy.
// position in the hierarchy.
class CdlParentableBody : virtual public CdlNodeBody {
class CdlParentableBody : virtual public CdlNodeBody {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlParentableBody();
    virtual ~CdlParentableBody();
    static void         add_property_parsers(std::vector& parsers);
    static void         add_property_parsers(std::vector& parsers);
    void                check_properties(CdlInterpreter);
    void                check_properties(CdlInterpreter);
    static int          parse_parent(CdlInterpreter, int, const char*[]);
    static int          parse_parent(CdlInterpreter, int, const char*[]);
    static void         update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlParentableBody();
    CdlParentableBody();
  private:
  private:
    // Unloads may be cancelled. To restore the previous state exactly
    // Unloads may be cancelled. To restore the previous state exactly
    // it is necessary to keep track of the old position.
    // it is necessary to keep track of the old position.
    int                 change_parent_save_position;
    int                 change_parent_save_position;
    enum {
    enum {
        CdlParentableBody_Invalid      = 0,
        CdlParentableBody_Invalid      = 0,
        CdlParentableBody_Magic        = 0x40c6a077
        CdlParentableBody_Magic        = 0x40c6a077
    } cdlparentablebody_cookie;
    } cdlparentablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlParentableBody(const CdlParentableBody&);
    CdlParentableBody(const CdlParentableBody&);
    CdlParentableBody& operator=(const CdlParentableBody&);
    CdlParentableBody& operator=(const CdlParentableBody&);
};
};
//}}}
//}}}
//{{{  CdlValuable
//{{{  CdlValuable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A valuable body has a value. Many valuables can be modified but not all.
// A valuable body has a value. Many valuables can be modified but not all.
// Some properties make a valuable object read-only. In future there is
// Some properties make a valuable object read-only. In future there is
// likely to be support for locked values as well. There is a member function
// likely to be support for locked values as well. There is a member function
// to check whether or not a valuable object is modifiable.
// to check whether or not a valuable object is modifiable.
//
//
// Relevant properties for a valuable object are:
// Relevant properties for a valuable object are:
//
//
//  1) flavor           - readily available via CdlValue::get_flavor()
//  1) flavor           - readily available via CdlValue::get_flavor()
//  2) default_value    - an expression
//  2) default_value    - an expression
//  3) legal_values     - a list expression
//  3) legal_values     - a list expression
//  4) entry_proc       - for validation purposes, in addition to legal_values
//  4) entry_proc       - for validation purposes, in addition to legal_values
//  5) check_proc       - ditto
//  5) check_proc       - ditto
//  6) active_if        - goal expression
//  6) active_if        - goal expression
//  7) requires         - goal expression
//  7) requires         - goal expression
//  8) dialog           - a custom dialog for editing this value
//  8) dialog           - a custom dialog for editing this value
//  9) calculated       - non-modifiable
//  9) calculated       - non-modifiable
// 10) implements       - for interfaces
// 10) implements       - for interfaces
//
//
// A CdlValuable does not inherit directly from CdlValue, since it should
// A CdlValuable does not inherit directly from CdlValue, since it should
// not be possible to modify a Valuable directly. Instead it contains a
// not be possible to modify a Valuable directly. Instead it contains a
// CdlValue member, and provides essentially the same functions as
// CdlValue member, and provides essentially the same functions as
// a CdlValue.
// a CdlValue.
class CdlValuableBody : virtual public CdlNodeBody {
class CdlValuableBody : virtual public CdlNodeBody {
    friend class CdlTest;
    friend class CdlTest;
    // Transaction commit operations require direct access to the CdlValue
    // Transaction commit operations require direct access to the CdlValue
    friend class CdlTransactionBody;
    friend class CdlTransactionBody;
  private:
  private:
    CdlValue value;
    CdlValue value;
  public:
  public:
    virtual ~CdlValuableBody();
    virtual ~CdlValuableBody();
    // Accessing the current value. There are variants for the global state
    // Accessing the current value. There are variants for the global state
    // and for per-transaction operations.
    // and for per-transaction operations.
    const CdlValue&     get_whole_value() const;
    const CdlValue&     get_whole_value() const;
    CdlValueFlavor      get_flavor() const;
    CdlValueFlavor      get_flavor() const;
    CdlValueFlavor      get_flavor(CdlTransaction transaction) const
    CdlValueFlavor      get_flavor(CdlTransaction transaction) const
    {   // The transaction is irrelevant, it cannot change the flavor
    {   // The transaction is irrelevant, it cannot change the flavor
        return this->get_flavor();
        return this->get_flavor();
    }
    }
    CdlValueSource      get_source() const;
    CdlValueSource      get_source() const;
    bool                has_source(        CdlValueSource) const;
    bool                has_source(        CdlValueSource) const;
    bool                is_enabled(        CdlValueSource = CdlValueSource_Current) const;
    bool                is_enabled(        CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(         CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(         CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value( CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value( CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value( CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value( CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(  CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(  CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(  CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(  CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(  CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(  CdlValueSource = CdlValueSource_Current) const;
    CdlValueSource      get_source(CdlTransaction) const;
    CdlValueSource      get_source(CdlTransaction) const;
    bool                has_source(        CdlTransaction, CdlValueSource) const;
    bool                has_source(        CdlTransaction, CdlValueSource) const;
    bool                is_enabled(        CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    bool                is_enabled(        CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(         CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    std::string         get_value(         CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    bool                has_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    cdl_int             get_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    bool                has_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    double              get_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    CdlSimpleValue      get_simple_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
    // -----------------------------------------------------------------
    // -----------------------------------------------------------------
    // Modify access. There are two variants of all the functions:
    // Modify access. There are two variants of all the functions:
    //
    //
    // 1) no transaction argument. A transaction will be created,
    // 1) no transaction argument. A transaction will be created,
    //    committed, and destroyed for the change in question.
    //    committed, and destroyed for the change in question.
    //
    //
    // 2) a transaction argument. The existing transaction will be
    // 2) a transaction argument. The existing transaction will be
    //    updated but not committed. This allows multiple changes
    //    updated but not committed. This allows multiple changes
    //    to be grouped together.
    //    to be grouped together.
    //
    //
    // There are only a handful of exported functions, but lots
    // There are only a handful of exported functions, but lots
    // of inline variants.
    // of inline variants.
    void set_source(CdlValueSource);
    void set_source(CdlValueSource);
    void invalidate_source(CdlValueSource);
    void invalidate_source(CdlValueSource);
    void set_enabled(bool, CdlValueSource);
    void set_enabled(bool, CdlValueSource);
    void set_value(CdlSimpleValue&, CdlValueSource);
    void set_value(CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
    void set(CdlSimpleValue&, CdlValueSource);
    void set(CdlSimpleValue&, CdlValueSource);
    void set_source(CdlTransaction, CdlValueSource);
    void set_source(CdlTransaction, CdlValueSource);
    void invalidate_source(CdlTransaction, CdlValueSource);
    void invalidate_source(CdlTransaction, CdlValueSource);
    void set_enabled(CdlTransaction, bool, CdlValueSource);
    void set_enabled(CdlTransaction, bool, CdlValueSource);
    void set_value(CdlTransaction, CdlSimpleValue&, CdlValueSource);
    void set_value(CdlTransaction, CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(CdlTransaction, bool, CdlSimpleValue&, CdlValueSource);
    void set_enabled_and_value(CdlTransaction, bool, CdlSimpleValue&, CdlValueSource);
    void set(CdlTransaction, CdlSimpleValue&, CdlValueSource);
    void set(CdlTransaction, CdlSimpleValue&, CdlValueSource);
    void set(CdlTransaction, const CdlValue&);
    void set(CdlTransaction, const CdlValue&);
    void enable(CdlValueSource source)
    void enable(CdlValueSource source)
    {
    {
        set_enabled(true, source);
        set_enabled(true, source);
    }
    }
    void disable(CdlValueSource source)
    void disable(CdlValueSource source)
    {
    {
        set_enabled(false, source);
        set_enabled(false, source);
    }
    }
    void set_value(std::string data, CdlValueSource source)
    void set_value(std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_integer_value(cdl_int data, CdlValueSource source)
    void set_integer_value(cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_double_value(double data, CdlValueSource source)
    void set_double_value(double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(val, source);
        set_value(val, source);
    }
    }
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(enabled, val, source);
        set_enabled_and_value(enabled, val, source);
    }
    }
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, val, source);
        set_enabled_and_value(true, val, source);
    }
    }
    void enable_and_set_value(std::string data, CdlValueSource source)
    void enable_and_set_value(std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void enable_and_set_value(cdl_int data, CdlValueSource source)
    void enable_and_set_value(cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void enable_and_set_value(double data, CdlValueSource source)
    void enable_and_set_value(double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(true, data, source);
        set_enabled_and_value(true, data, source);
    }
    }
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, val, source);
        set_enabled_and_value(false, val, source);
    }
    }
    void disable_and_set_value(std::string data, CdlValueSource source)
    void disable_and_set_value(std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void disable_and_set_value(cdl_int data, CdlValueSource source)
    void disable_and_set_value(cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void disable_and_set_value(double data, CdlValueSource source)
    void disable_and_set_value(double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(false, data, source);
        set_enabled_and_value(false, data, source);
    }
    }
    void enable(CdlTransaction transaction, CdlValueSource source)
    void enable(CdlTransaction transaction, CdlValueSource source)
    {
    {
        set_enabled(transaction, true, source);
        set_enabled(transaction, true, source);
    }
    }
    void disable(CdlTransaction transaction, CdlValueSource source)
    void disable(CdlTransaction transaction, CdlValueSource source)
    {
    {
        set_enabled(transaction, false, source);
        set_enabled(transaction, false, source);
    }
    }
    void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(transaction, val, source);
        set_value(transaction, val, source);
    }
    }
    void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(transaction, val, source);
        set_value(transaction, val, source);
    }
    }
    void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
    void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_value(transaction, val, source);
        set_value(transaction, val, source);
    }
    }
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(transaction, enabled, val, source);
        set_enabled_and_value(transaction, enabled, val, source);
    }
    }
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(transaction, enabled, val, source);
        set_enabled_and_value(transaction, enabled, val, source);
    }
    }
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
    {
    {
        CdlSimpleValue val(data);
        CdlSimpleValue val(data);
        set_enabled_and_value(transaction, enabled, val, source);
        set_enabled_and_value(transaction, enabled, val, source);
    }
    }
    void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
    void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, true, val, source);
        set_enabled_and_value(transaction, true, val, source);
    }
    }
    void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, true, data, source);
        set_enabled_and_value(transaction, true, data, source);
    }
    }
    void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, true, data, source);
        set_enabled_and_value(transaction, true, data, source);
    }
    }
    void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
    void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, true, data, source);
        set_enabled_and_value(transaction, true, data, source);
    }
    }
    void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
    void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, false, val, source);
        set_enabled_and_value(transaction, false, val, source);
    }
    }
    void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, false, data, source);
        set_enabled_and_value(transaction, false, data, source);
    }
    }
    void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, false, data, source);
        set_enabled_and_value(transaction, false, data, source);
    }
    }
    void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
    void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
    {
    {
        set_enabled_and_value(transaction, false, data, source);
        set_enabled_and_value(transaction, false, data, source);
    }
    }
    // -----------------------------------------------------------------
    // -----------------------------------------------------------------
    virtual bool   is_modifiable() const;
    virtual bool   is_modifiable() const;
    void           get_widget_hint(CdlWidgetHint&);
    void           get_widget_hint(CdlWidgetHint&);
    // -----------------------------------------------------------------
    // -----------------------------------------------------------------
    // Propagation support. If a valuable becomes active or inactive
    // Propagation support. If a valuable becomes active or inactive
    // because e.g. its parent is disabled then this may affect
    // because e.g. its parent is disabled then this may affect
    // requires conflicts etc.
    // requires conflicts etc.
    virtual void update(CdlTransaction, CdlUpdate);
    virtual void update(CdlTransaction, CdlUpdate);
    virtual bool test_active(CdlTransaction);
    virtual bool test_active(CdlTransaction);
    // -----------------------------------------------------------------
    // -----------------------------------------------------------------
    // Property-related stuff.
    // Property-related stuff.
    bool                                has_calculated_expression() const;
    bool                                has_calculated_expression() const;
    bool                                has_default_value_expression() const;
    bool                                has_default_value_expression() const;
    bool                                has_legal_values() const;
    bool                                has_legal_values() const;
    bool                                has_entry_proc() const;
    bool                                has_entry_proc() const;
    bool                                has_check_proc() const;
    bool                                has_check_proc() const;
    bool                                has_active_if_conditions() const;
    bool                                has_active_if_conditions() const;
    bool                                has_requires_goals() const;
    bool                                has_requires_goals() const;
    bool                                has_dialog() const;
    bool                                has_dialog() const;
    bool                                has_wizard() const;
    bool                                has_wizard() const;
    CdlProperty_Expression              get_calculated_expression() const;
    CdlProperty_Expression              get_calculated_expression() const;
    CdlProperty_Expression              get_default_value_expression() const;
    CdlProperty_Expression              get_default_value_expression() const;
    CdlProperty_ListExpression          get_legal_values() const;
    CdlProperty_ListExpression          get_legal_values() const;
    cdl_tcl_code                        get_entry_proc() const;
    cdl_tcl_code                        get_entry_proc() const;
    cdl_tcl_code                        get_check_proc() const;
    cdl_tcl_code                        get_check_proc() const;
    void                                get_active_if_conditions(std::vector&) const;
    void                                get_active_if_conditions(std::vector&) const;
    void                                get_requires_goals(std::vector&) const;
    void                                get_requires_goals(std::vector&) const;
    CdlDialog                           get_dialog() const;
    CdlDialog                           get_dialog() const;
    CdlWizard                           get_wizard() const;
    CdlWizard                           get_wizard() const;
    void                                get_implemented_interfaces(std::vector&) const;
    void                                get_implemented_interfaces(std::vector&) const;
    // Add property parsers and validation code appropriate for a
    // Add property parsers and validation code appropriate for a
    // valuable object such as default_value and legal_values
    // valuable object such as default_value and legal_values
    static void         add_property_parsers(std::vector& parsers);
    static void         add_property_parsers(std::vector& parsers);
    void                check_properties(CdlInterpreter);
    void                check_properties(CdlInterpreter);
    static int          parse_active_if(CdlInterpreter, int, const char*[]);
    static int          parse_active_if(CdlInterpreter, int, const char*[]);
    static void         active_if_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         active_if_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_calculated(CdlInterpreter, int, const char*[]);
    static int          parse_calculated(CdlInterpreter, int, const char*[]);
    static void         calculated_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         calculated_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_check_proc(CdlInterpreter, int, const char*[]);
    static int          parse_check_proc(CdlInterpreter, int, const char*[]);
    static int          parse_default_value(CdlInterpreter, int, const char*[]);
    static int          parse_default_value(CdlInterpreter, int, const char*[]);
    static void         default_value_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         default_value_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
    static void         dialog_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         dialog_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_entry_proc(CdlInterpreter, int, const char*[]);
    static int          parse_entry_proc(CdlInterpreter, int, const char*[]);
    static int          parse_flavor(CdlInterpreter, int, const char*[]);
    static int          parse_flavor(CdlInterpreter, int, const char*[]);
    static int          parse_group(CdlInterpreter, int, const char*[]);
    static int          parse_group(CdlInterpreter, int, const char*[]);
    static int          parse_implements(CdlInterpreter, int, const char*[]);
    static int          parse_implements(CdlInterpreter, int, const char*[]);
    static void         implements_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         implements_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_legal_values(CdlInterpreter, int, const char*[]);
    static int          parse_legal_values(CdlInterpreter, int, const char*[]);
    static void         legal_values_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         legal_values_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_requires(CdlInterpreter, int, const char*[]);
    static int          parse_requires(CdlInterpreter, int, const char*[]);
    static void         requires_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         requires_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
    static void         wizard_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    static void         wizard_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
    // Persistence suppot
    // Persistence suppot
    void save(CdlInterpreter, Tcl_Channel, int, bool /* modifiable */, bool /* minimal */);
    void save(CdlInterpreter, Tcl_Channel, int, bool /* modifiable */, bool /* minimal */);
    bool value_savefile_entry_needed() const;
    bool value_savefile_entry_needed() const;
    static void initialize_savefile_support(CdlToplevel, std::string);
    static void initialize_savefile_support(CdlToplevel, std::string);
    static int  savefile_value_source_command(CdlInterpreter, int, const char*[]);
    static int  savefile_value_source_command(CdlInterpreter, int, const char*[]);
    static int  savefile_user_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_user_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_wizard_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_wizard_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_inferred_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_inferred_value_command(CdlInterpreter, int, const char*[]);
    static int  savefile_xxx_value_command(CdlInterpreter, int, const char*[], CdlValueSource);
    static int  savefile_xxx_value_command(CdlInterpreter, int, const char*[], CdlValueSource);
    // Make sure that the current value is legal. This gets called automatically
    // Make sure that the current value is legal. This gets called automatically
    // by all the members that modify values. It has to be a virtual function
    // by all the members that modify values. It has to be a virtual function
    // since some derived classes, e.g. hardware-related valuables, may impose
    // since some derived classes, e.g. hardware-related valuables, may impose
    // constraints over and above legal_values etc.
    // constraints over and above legal_values etc.
    virtual void check_value(CdlTransaction);
    virtual void check_value(CdlTransaction);
    // Similarly check the requires properties
    // Similarly check the requires properties
    void check_requires(CdlTransaction, CdlProperty_GoalExpression);
    void check_requires(CdlTransaction, CdlProperty_GoalExpression);
    void check_requires(CdlTransaction);
    void check_requires(CdlTransaction);
    // Enabling or disabling a valuable may affect the active state of children
    // Enabling or disabling a valuable may affect the active state of children
    void check_children_active(CdlTransaction);
    void check_children_active(CdlTransaction);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
    CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
  private:
  private:
    enum {
    enum {
        CdlValuableBody_Invalid = 0,
        CdlValuableBody_Invalid = 0,
        CdlValuableBody_Magic   = 0x2b2acc03
        CdlValuableBody_Magic   = 0x2b2acc03
    } cdlvaluablebody_cookie;
    } cdlvaluablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlValuableBody(const CdlValuableBody&);
    CdlValuableBody(const CdlValuableBody&);
    CdlValuableBody& operator=(const CdlValuableBody&);
    CdlValuableBody& operator=(const CdlValuableBody&);
};
};
//}}}
//}}}
//{{{  CdlTransaction etc.
//{{{  CdlTransaction etc.
//{{{  Description
//{{{  Description
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Transactions. These are used for all changes to a configuration. In some
// Transactions. These are used for all changes to a configuration. In some
// cases a transaction is implicit:
// cases a transaction is implicit:
//
//
//    valuable->set_value(...)
//    valuable->set_value(...)
//
//
// The actual implementation of this is:
// The actual implementation of this is:
//
//
//    valuable->set_value(...)
//    valuable->set_value(...)
//        transact = CdlTransactionBody::make(valuable->get_toplevel())
//        transact = CdlTransactionBody::make(valuable->get_toplevel())
//        valuable->set_value(transact, ...)
//        valuable->set_value(transact, ...)
//        
//        
//        transact->commit()
//        transact->commit()
//        delete transact
//        delete transact
//
//
// Alternatively the use of transactions may be explicit. For implicit
// Alternatively the use of transactions may be explicit. For implicit
// uses the library will invoke an inference callback at the
// uses the library will invoke an inference callback at the
// appropriate time. For explicit transactions this is not necessary.
// appropriate time. For explicit transactions this is not necessary.
//
//
// The commit() operation invokes a transaction callback which should
// The commit() operation invokes a transaction callback which should
// not be confused with the inference callback. The former is intended
// not be confused with the inference callback. The former is intended
// for display updates, it specifies everything that has changed
// for display updates, it specifies everything that has changed
// during the transaction. The latter is used for reporting new
// during the transaction. The latter is used for reporting new
// conflicts to the user, suggesting fixes, etc.
// conflicts to the user, suggesting fixes, etc.
//
//
// A whole bunch of information is associated with a transaction,
// A whole bunch of information is associated with a transaction,
// including: all value changes, details of new conflicts, and details
// including: all value changes, details of new conflicts, and details
// of existing conflicts that have gone away. The commit operation
// of existing conflicts that have gone away. The commit operation
// takes care of updating the toplevel. Until the commit happens
// takes care of updating the toplevel. Until the commit happens
// the toplevel itself remains unchanged. It is also possible to cancel
// the toplevel itself remains unchanged. It is also possible to cancel
// a transaction.
// a transaction.
//
//
// An important concept related to transactions is propagation.
// An important concept related to transactions is propagation.
// Changing a value may have various effects, for example it may
// Changing a value may have various effects, for example it may
// change the result of a legal_values list expression, resulting in a
// change the result of a legal_values list expression, resulting in a
// conflict object having to be created or destroyed. Changing one
// conflict object having to be created or destroyed. Changing one
// value may result in other value changes, e.g. because of a
// value may result in other value changes, e.g. because of a
// default_value property. All this is "propagation", and may
// default_value property. All this is "propagation", and may
// happen multiple times within a single transaction.
// happen multiple times within a single transaction.
//
//
// Transaction objects are also used during load or unload operations,
// Transaction objects are also used during load or unload operations,
// but those are a little bit special. In particular it is not possible
// but those are a little bit special. In particular it is not possible
// to cancel such a transaction, there will have been updates to the
// to cancel such a transaction, there will have been updates to the
// toplevel. Using a transaction is convenient because there is a
// toplevel. Using a transaction is convenient because there is a
// need for propagation.
// need for propagation.
//
//
// Currently a transaction should be deleted immediately after a
// Currently a transaction should be deleted immediately after a
// commit or cancel. This may change in future, in that transaction
// commit or cancel. This may change in future, in that transaction
// objects can be used to hold undo information.
// objects can be used to hold undo information.
//
//
//
//
// The other big concept related to transactions is inference.
// The other big concept related to transactions is inference.
// Changing a value may result in one or more new conflicts being
// Changing a value may result in one or more new conflicts being
// created. In some cases the library can figure out for itself how to
// created. In some cases the library can figure out for itself how to
// resolve these conflicts, using an inference engine. There are
// resolve these conflicts, using an inference engine. There are
// parameters to control the operation of the inference engine,
// parameters to control the operation of the inference engine,
// including whether it runs at all, what changes it is allowed
// including whether it runs at all, what changes it is allowed
// to make automatically (usually default and inferred values can
// to make automatically (usually default and inferred values can
// be updated, but not wizard or user values), and how much
// be updated, but not wizard or user values), and how much
// recursion will happen.
// recursion will happen.
//
//
// Assuming a default setup in a GUI environment, a typical
// Assuming a default setup in a GUI environment, a typical
// sequence of events would be:
// sequence of events would be:
//
//
//     valuable->set_value(...)
//     valuable->set_value(...)
//         transact = CdlTransactionBody::make(valuable->get_toplevel())
//         transact = CdlTransactionBody::make(valuable->get_toplevel())
//         valuable->set_value(transact, ...)
//         valuable->set_value(transact, ...)
//             transact->set_whole_value(valuable, ...)
//             transact->set_whole_value(valuable, ...)
//         transact->propagate()
//         transact->propagate()
//         while (!finished)
//         while (!finished)
//             transact->resolve()
//             transact->resolve()
//                 
//                 
//             invoke inference callback
//             invoke inference callback
//                 transact->apply_solution() (1 or more times)
//                 transact->apply_solution() (1 or more times)
//                     transact->set_whole_value(valuable, ...) (1 or more times)
//                     transact->set_whole_value(valuable, ...) (1 or more times)
//             transact->propagate()
//             transact->propagate()
//         transact->commit() | transact->cancel()
//         transact->commit() | transact->cancel()
//         delete transact
//         delete transact
//
//
// Note that the propagation steps have to be invoked explicitly,
// Note that the propagation steps have to be invoked explicitly,
// allowing multiple changes to be processed in one go. There is
// allowing multiple changes to be processed in one go. There is
// a utility function which combines the functionality from
// a utility function which combines the functionality from
// the first propagate() call up to but not including the
// the first propagate() call up to but not including the
// transaction delete operator.
// transaction delete operator.
//
//
//
//
// The inference engine itself is a complicated beast. There are
// The inference engine itself is a complicated beast. There are
// a number of interfaces, but at the end of the day it ends up
// a number of interfaces, but at the end of the day it ends up
// creating a sub-transaction and trying to resolve a single
// creating a sub-transaction and trying to resolve a single
// conflict in that sub-transaction. The conflict may belong to
// conflict in that sub-transaction. The conflict may belong to
// the current transaction or it may be global.
// the current transaction or it may be global.
//
//
//     
//     
//         for each conflict of interest
//         for each conflict of interest
//             make sure that there is not already a valid solution
//             make sure that there is not already a valid solution
//             check that the inference engine can handle it
//             check that the inference engine can handle it
//             create a sub-transaction, associated with the conflict
//             create a sub-transaction, associated with the conflict
//             apply the conflict resolution code
//             apply the conflict resolution code
//             if the solution is ok
//             if the solution is ok
//                 install it
//                 install it
//             else if the solution might e.g. overwrite a user value
//             else if the solution might e.g. overwrite a user value
//                 keep it, the user can decide during the inference callback
//                 keep it, the user can decide during the inference callback
//
//
// The conflict resolution typically works by attempting to change
// The conflict resolution typically works by attempting to change
// one or more values in the sub-transaction, propagating them,
// one or more values in the sub-transaction, propagating them,
// and seeing what new conflicts get created. If no new conflicts
// and seeing what new conflicts get created. If no new conflicts
// get created and one or more existing conflicts go away, groovy.
// get created and one or more existing conflicts go away, groovy.
// Otherwise recursion can be used to try to resolve the new
// Otherwise recursion can be used to try to resolve the new
// conflicts, or other strategies can be explored.
// conflicts, or other strategies can be explored.
//
//
// NOTE: what is really necessary is some way of keeping track of the
// NOTE: what is really necessary is some way of keeping track of the
// "best" solution to date, and allow exploration of alternatives.
// "best" solution to date, and allow exploration of alternatives.
// Or possibly keep track of all solutions. That has to be left to
// Or possibly keep track of all solutions. That has to be left to
// a future version.
// a future version.
//}}}
//}}}
//{{{  CdlTransactionCommitCancelOp
//{{{  CdlTransactionCommitCancelOp
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The CdlTransaction class has built-in knowledge of how to handle values,
// The CdlTransaction class has built-in knowledge of how to handle values,
// active state, and a few things like that. However there are also more
// active state, and a few things like that. However there are also more
// complicated operations such as loading and unloading, instantiating
// complicated operations such as loading and unloading, instantiating
// items, etc. which also need to happen in the context of a transaction
// items, etc. which also need to happen in the context of a transaction
// but which the transaction class does not necessarily know about
// but which the transaction class does not necessarily know about
// itself - or at least, not in any detail. Since the libcdl core is
// itself - or at least, not in any detail. Since the libcdl core is
// intended to be useful in various contexts, some sort of extensibility
// intended to be useful in various contexts, some sort of extensibility
// is essential.
// is essential.
//
//
// This is achieved by an auxiliary class, CdlTransactionCommitCancelOp.
// This is achieved by an auxiliary class, CdlTransactionCommitCancelOp.
// Clients of the transaction class can have their own utility class
// Clients of the transaction class can have their own utility class
// which derives from this, and create suitable objects. The transaction
// which derives from this, and create suitable objects. The transaction
// class maintains a vector of the pending commit/cancel operations.
// class maintains a vector of the pending commit/cancel operations.
//
//
// Each CdlTransactionCommitCancelOp object has two member functions,
// Each CdlTransactionCommitCancelOp object has two member functions,
// one for when the transaction gets committed and one for when it
// one for when the transaction gets committed and one for when it
// gets cancelled. If a sub-transaction gets committed then its
// gets cancelled. If a sub-transaction gets committed then its
// pending ops are transferred across to the parent, allowing the
// pending ops are transferred across to the parent, allowing the
// parent to be cancelled sensibly: the commit ops only get run for
// parent to be cancelled sensibly: the commit ops only get run for
// the toplevel transaction. If a sub-transaction gets cancelled then
// the toplevel transaction. If a sub-transaction gets cancelled then
// the pending ops are invoked immediately.
// the pending ops are invoked immediately.
//
//
// There is an assumption that commit/cancel ops get executed strictly
// There is an assumption that commit/cancel ops get executed strictly
// in FIFO order. Specifically, commit ops get run from first one to
// in FIFO order. Specifically, commit ops get run from first one to
// the last one, allowing later operations in the transaction to
// the last one, allowing later operations in the transaction to
// overwrite earlier ones. Cancel ops get run in reverse order.
// overwrite earlier ones. Cancel ops get run in reverse order.
class CdlTransactionCommitCancelOp {
class CdlTransactionCommitCancelOp {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    CdlTransactionCommitCancelOp() { }
    CdlTransactionCommitCancelOp() { }
    virtual ~CdlTransactionCommitCancelOp() { };
    virtual ~CdlTransactionCommitCancelOp() { };
    // The default implementations of both of these do nothing.
    // The default implementations of both of these do nothing.
    // Derived classes should override at least one of these
    // Derived classes should override at least one of these
    // functions.
    // functions.
    virtual void commit(CdlTransaction transaction) {
    virtual void commit(CdlTransaction transaction) {
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
    }
    }
    virtual void cancel(CdlTransaction transaction) {
    virtual void cancel(CdlTransaction transaction) {
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
    }
    }
  protected:
  protected:
  private:
  private:
};
};
//}}}
//}}}
//{{{  CdlTransaction class
//{{{  CdlTransaction class
class CdlTransactionBody {
class CdlTransactionBody {
    friend class CdlTest;
    friend class CdlTest;
    friend class CdlConflictBody;
    friend class CdlConflictBody;
    friend class CdlValuableBody;
    friend class CdlValuableBody;
  public:
  public:
    // Create a toplevel transaction
    // Create a toplevel transaction
    static CdlTransaction make(CdlToplevel);
    static CdlTransaction make(CdlToplevel);
    virtual ~CdlTransactionBody();
    virtual ~CdlTransactionBody();
    CdlToplevel get_toplevel() const;
    CdlToplevel get_toplevel() const;
    // Or a sub-transaction. Usually these are created in the context of
    // Or a sub-transaction. Usually these are created in the context of
    // a conflict that is being resolved.
    // a conflict that is being resolved.
    CdlTransaction make(CdlConflict = 0);
    CdlTransaction make(CdlConflict = 0);
    CdlTransaction get_parent() const;
    CdlTransaction get_parent() const;
    CdlConflict    get_conflict() const;
    CdlConflict    get_conflict() const;
    // Commit all the changes. Essentially this means transferring
    // Commit all the changes. Essentially this means transferring
    // all of the per-transaction data to the toplevel, and then
    // all of the per-transaction data to the toplevel, and then
    // invoking the transaction callback. All propagation, inference,
    // invoking the transaction callback. All propagation, inference,
    // etc. should happen before the commit()
    // etc. should happen before the commit()
    // This routine can also be used to transfer changes from a
    // This routine can also be used to transfer changes from a
    // sub-transaction to the parent.
    // sub-transaction to the parent.
    void        commit();
    void        commit();
    // A variant of the commit() operation can be used to
    // A variant of the commit() operation can be used to
    // store a sub-transaction in a conflict's solution vector,
    // store a sub-transaction in a conflict's solution vector,
    // rather than updating the parent transaction. This is useful
    // rather than updating the parent transaction. This is useful
    // for inferred solutions which cannot be applied without
    // for inferred solutions which cannot be applied without
    // user confirmation
    // user confirmation
    void        save_solution();
    void        save_solution();
    // Can a solution held in a sub-transaction be applied without
    // Can a solution held in a sub-transaction be applied without
    // e.g. overwriting a user value with an inferred value?
    // e.g. overwriting a user value with an inferred value?
    bool        user_confirmation_required() const;
    bool        user_confirmation_required() const;
    // If the user has explicitly changed a value in the current transaction
    // If the user has explicitly changed a value in the current transaction
    // then the inference engine should not undo this or suggest a solution
    // then the inference engine should not undo this or suggest a solution
    // that will undo the change.
    // that will undo the change.
    bool        changed_by_user(CdlValuable) const;
    bool        changed_by_user(CdlValuable) const;
    // A variant which is used for checking the hierarchy when disabling
    // A variant which is used for checking the hierarchy when disabling
    // a container
    // a container
    bool        subnode_changed_by_user(CdlContainer) const;
    bool        subnode_changed_by_user(CdlContainer) const;
    // Is one transaction preferable to another?
    // Is one transaction preferable to another?
    bool        is_preferable_to(CdlTransaction) const;
    bool        is_preferable_to(CdlTransaction) const;
    // Find out about per-transaction conflicts. This is particularly
    // Find out about per-transaction conflicts. This is particularly
    // useful for the inference callback. The other containers can
    // useful for the inference callback. The other containers can
    // be accessed as well, for completeness.
    // be accessed as well, for completeness.
    const std::list&       get_new_conflicts() const;
    const std::list&       get_new_conflicts() const;
    const std::list&       get_new_structural_conflicts() const;
    const std::list&       get_new_structural_conflicts() const;
    const std::vector&     get_deleted_conflicts() const;
    const std::vector&     get_deleted_conflicts() const;
    const std::vector&     get_deleted_structural_conflicts() const;
    const std::vector&     get_deleted_structural_conflicts() const;
    const std::vector&     get_resolved_conflicts() const ;
    const std::vector&     get_resolved_conflicts() const ;
    const std::list&       get_global_conflicts_with_solutions() const;
    const std::list&       get_global_conflicts_with_solutions() const;
    const std::map& get_changes() const;
    const std::map& get_changes() const;
    const std::set&            get_activated() const;
    const std::set&            get_activated() const;
    const std::set&            get_deactivated() const;
    const std::set&            get_deactivated() const;
    const std::set&        get_legal_values_changes() const;
    const std::set&        get_legal_values_changes() const;
    // Manipulate the current set of conflicts, allowing for nested
    // Manipulate the current set of conflicts, allowing for nested
    // transactions and toplevel conflicts as well.
    // transactions and toplevel conflicts as well.
    void        clear_conflict(CdlConflict);
    void        clear_conflict(CdlConflict);
    bool        has_conflict_been_cleared(CdlConflict);
    bool        has_conflict_been_cleared(CdlConflict);
    bool        has_conflict(CdlNode, bool (*)(CdlConflict));
    bool        has_conflict(CdlNode, bool (*)(CdlConflict));
    CdlConflict get_conflict(CdlNode, bool (*)(CdlConflict));
    CdlConflict get_conflict(CdlNode, bool (*)(CdlConflict));
    void        get_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
    void        get_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
    void        clear_conflicts(CdlNode, bool (*)(CdlConflict));
    void        clear_conflicts(CdlNode, bool (*)(CdlConflict));
    bool        has_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    bool        has_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    CdlConflict get_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    CdlConflict get_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    void        get_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
    void        get_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
    void        clear_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
    void        clear_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
    bool        has_structural_conflict(CdlNode, bool (*)(CdlConflict));
    bool        has_structural_conflict(CdlNode, bool (*)(CdlConflict));
    CdlConflict get_structural_conflict(CdlNode, bool (*)(CdlConflict));
    CdlConflict get_structural_conflict(CdlNode, bool (*)(CdlConflict));
    void        get_structural_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
    void        get_structural_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
    void        clear_structural_conflicts(CdlNode, bool (*)(CdlConflict));
    void        clear_structural_conflicts(CdlNode, bool (*)(CdlConflict));
    bool        has_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    bool        has_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    CdlConflict get_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    CdlConflict get_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
    void        get_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
    void        get_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
    void        clear_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
    void        clear_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
    // During the inference callback the user may decide to
    // During the inference callback the user may decide to
    // apply one or more of the solutions.
    // apply one or more of the solutions.
    void        apply_solution(CdlConflict);
    void        apply_solution(CdlConflict);
    void        apply_solutions(const std::vector&);
    void        apply_solutions(const std::vector&);
    void        apply_all_solutions();
    void        apply_all_solutions();
    // Cancel all the changes done in this transaction. Essentially
    // Cancel all the changes done in this transaction. Essentially
    // this just involves clearing out all the STL containers.
    // this just involves clearing out all the STL containers.
    void        cancel();
    void        cancel();
    // Support for commit/cancel ops. These are used for
    // Support for commit/cancel ops. These are used for
    // e.g. load and unload operations.
    // e.g. load and unload operations.
    void        add_commit_cancel_op(CdlTransactionCommitCancelOp *);
    void        add_commit_cancel_op(CdlTransactionCommitCancelOp *);
    void        cancel_last_commit_cancel_op();
    void        cancel_last_commit_cancel_op();
    CdlTransactionCommitCancelOp* get_last_commit_cancel_op() const;
    CdlTransactionCommitCancelOp* get_last_commit_cancel_op() const;
    const std::vector& get_commit_cancel_ops() const;
    const std::vector& get_commit_cancel_ops() const;
    // Propagation support
    // Propagation support
    void        add_active_change(CdlNode);
    void        add_active_change(CdlNode);
    void        add_legal_values_change(CdlValuable);
    void        add_legal_values_change(CdlValuable);
    void        propagate();
    void        propagate();
    bool        is_propagation_required() const;
    bool        is_propagation_required() const;
    // Inference engine support.
    // Inference engine support.
    void        resolve(int = 0); // Process the new conflicts raised by this transaction
    void        resolve(int = 0); // Process the new conflicts raised by this transaction
    void        resolve(CdlConflict, int = 0);
    void        resolve(CdlConflict, int = 0);
    void        resolve(const std::vector&, int = 0);
    void        resolve(const std::vector&, int = 0);
    // An auxiliary function called by the inference engine to perform recursion
    // An auxiliary function called by the inference engine to perform recursion
    bool        resolve_recursion(int);
    bool        resolve_recursion(int);
    // This function combines propagation, inference, and commit
    // This function combines propagation, inference, and commit
    // in one easy-to-use package
    // in one easy-to-use package
    void        body();
    void        body();
    // Changes.
    // Changes.
    // There is a call to get hold of a CdlValue reference. Modifications
    // There is a call to get hold of a CdlValue reference. Modifications
    // should happen via a sequence of the form:
    // should happen via a sequence of the form:
    //
    //
    //    valuable->set_value(transact, ...)
    //    valuable->set_value(transact, ...)
    //        const CdlValue& old_value = transact->get_whole_value(CdlValuable);
    //        const CdlValue& old_value = transact->get_whole_value(CdlValuable);
    //        CdlValue new_value = old_value;
    //        CdlValue new_value = old_value;
    //        
    //        
    //        transact->set_whole_value(CdlValuable, old_value, new_value);
    //        transact->set_whole_value(CdlValuable, old_value, new_value);
    //
    //
    // When appropriate the get_whole_value() call takes care of
    // When appropriate the get_whole_value() call takes care of
    // updating the current conflict's solution_references vector. The
    // updating the current conflict's solution_references vector. The
    // set_whole_value() call updated the per-transaction changes map,
    // set_whole_value() call updated the per-transaction changes map,
    // and also stores sufficient information to support propagation.
    // and also stores sufficient information to support propagation.
    // set_whole_value() requires both the old and new values, so
    // set_whole_value() requires both the old and new values, so
    // that propagation can be optimized.
    // that propagation can be optimized.
    const CdlValue&     get_whole_value(CdlConstValuable) const;
    const CdlValue&     get_whole_value(CdlConstValuable) const;
    void                set_whole_value(CdlValuable, const CdlValue&, const CdlValue&);
    void                set_whole_value(CdlValuable, const CdlValue&, const CdlValue&);
    // Control over active vs. inactive also needs to happen inside
    // Control over active vs. inactive also needs to happen inside
    // transactions
    // transactions
    bool                is_active(CdlNode) const;
    bool                is_active(CdlNode) const;
    void                set_active(CdlNode, bool);
    void                set_active(CdlNode, bool);
    // Callback and parameter settings
    // Callback and parameter settings
    static void (*get_callback_fn())(const CdlTransactionCallback&);
    static void (*get_callback_fn())(const CdlTransactionCallback&);
    static void                 set_callback_fn(void (*)(const CdlTransactionCallback&));
    static void                 set_callback_fn(void (*)(const CdlTransactionCallback&));
    static void                 set_inference_callback_fn(CdlInferenceCallback);
    static void                 set_inference_callback_fn(CdlInferenceCallback);
    static CdlInferenceCallback get_inference_callback_fn();
    static CdlInferenceCallback get_inference_callback_fn();
    static void                 enable_automatic_inference();
    static void                 enable_automatic_inference();
    static void                 disable_automatic_inference();
    static void                 disable_automatic_inference();
    static bool                 is_automatic_inference_enabled();
    static bool                 is_automatic_inference_enabled();
    static void                 set_inference_recursion_limit(int);
    static void                 set_inference_recursion_limit(int);
    static int                  get_inference_recursion_limit();
    static int                  get_inference_recursion_limit();
    // The override indicates the highest level of value source that the
    // The override indicates the highest level of value source that the
    // library can overwrite without needing user confirmation. The
    // library can overwrite without needing user confirmation. The
    // default value is CdlValueSource_Inferred, indicating that the
    // default value is CdlValueSource_Inferred, indicating that the
    // library can overwrite default and inferred values but not
    // library can overwrite default and inferred values but not
    // wizard or user values.
    // wizard or user values.
    static void                 set_inference_override(CdlValueSource);
    static void                 set_inference_override(CdlValueSource);
    static CdlValueSource       get_inference_override();
    static CdlValueSource       get_inference_override();
    bool        check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool        check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
  private:
  private:
    CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
    CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
    // The associated toplevel and optionally the parent transaction
    // The associated toplevel and optionally the parent transaction
    // and the conflict being worked on
    // and the conflict being worked on
    CdlToplevel         toplevel;
    CdlToplevel         toplevel;
    CdlTransaction      parent;
    CdlTransaction      parent;
    CdlConflict         conflict;
    CdlConflict         conflict;
    // Per-transaction information. All value changes, new conflicts
    // Per-transaction information. All value changes, new conflicts
    // etc. first live in the context of a transaction. The global
    // etc. first live in the context of a transaction. The global
    // configuration only gets updated if the transaction is commited.
    // configuration only gets updated if the transaction is commited.
    // There is also a vector of the pending commit/cancel ops.
    // There is also a vector of the pending commit/cancel ops.
    std::vector commit_cancel_ops;
    std::vector commit_cancel_ops;
    std::map changes;
    std::map changes;
    std::list          new_conflicts;
    std::list          new_conflicts;
    std::list          new_structural_conflicts;
    std::list          new_structural_conflicts;
    std::vector        deleted_conflicts;  // Existing global ones
    std::vector        deleted_conflicts;  // Existing global ones
    std::vector        deleted_structural_conflicts;
    std::vector        deleted_structural_conflicts;
    std::vector        resolved_conflicts; // New ones already fixed by the inference engine
    std::vector        resolved_conflicts; // New ones already fixed by the inference engine
    std::list          global_conflicts_with_solutions;
    std::list          global_conflicts_with_solutions;
    std::set               activated;
    std::set               activated;
    std::set               deactivated;
    std::set               deactivated;
    std::set           legal_values_changes;
    std::set           legal_values_changes;
    bool                            dirty;
    bool                            dirty;
    // Change propagation. It is necessary to keep track of all
    // Change propagation. It is necessary to keep track of all
    // pending value changes, active changes, and of things being
    // pending value changes, active changes, and of things being
    // loaded or unloaded. The set_value() call is used to update the
    // loaded or unloaded. The set_value() call is used to update the
    // value_changes container.
    // value_changes container.
    std::deque     value_changes;
    std::deque     value_changes;
    std::deque         active_changes;
    std::deque         active_changes;
    // Control over the inference engine etc.
    // Control over the inference engine etc.
    static CdlInferenceCallback inference_callback;
    static CdlInferenceCallback inference_callback;
    static bool                 inference_enabled;
    static bool                 inference_enabled;
    static int                  inference_recursion_limit;
    static int                  inference_recursion_limit;
    static CdlValueSource       inference_override;
    static CdlValueSource       inference_override;
    static void (*callback_fn)(const CdlTransactionCallback&);
    static void (*callback_fn)(const CdlTransactionCallback&);
    enum {
    enum {
        CdlTransactionBody_Invalid = 0,
        CdlTransactionBody_Invalid = 0,
        CdlTransactionBody_Magic   = 0x3f91e4df
        CdlTransactionBody_Magic   = 0x3f91e4df
    } cdltransactionbody_cookie;
    } cdltransactionbody_cookie;
    // Illegal operations
    // Illegal operations
    CdlTransactionBody();
    CdlTransactionBody();
    CdlTransactionBody(const CdlTransactionBody &);
    CdlTransactionBody(const CdlTransactionBody &);
    CdlTransactionBody& operator=(const CdlTransactionBody&);
    CdlTransactionBody& operator=(const CdlTransactionBody&);
};
};
//}}}
//}}}
//{{{  CdlTransactionCallback
//{{{  CdlTransactionCallback
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// The callback class is used to inform applications about all the
// The callback class is used to inform applications about all the
// changes that are happening, including side effects. Application
// changes that are happening, including side effects. Application
// code can install a callback function which gets invoked at the
// code can install a callback function which gets invoked at the
// end of every transaction.
// end of every transaction.
//
//
// NOTE: this implementation is preliminary. In particular it is
// NOTE: this implementation is preliminary. In particular it is
// not extensible, it only deals with changes relevant to software
// not extensible, it only deals with changes relevant to software
// configurations.
// configurations.
class CdlTransactionCallback {
class CdlTransactionCallback {
    friend class CdlTest;
    friend class CdlTest;
    friend class CdlTransactionBody;
    friend class CdlTransactionBody;
  public:
  public:
    ~CdlTransactionCallback();
    ~CdlTransactionCallback();
    static void (*get_callback_fn())(const CdlTransactionCallback&);
    static void (*get_callback_fn())(const CdlTransactionCallback&);
    static void set_callback_fn(void (*)(const CdlTransactionCallback&));
    static void set_callback_fn(void (*)(const CdlTransactionCallback&));
    // Callback functions should be able to retrieve information
    // Callback functions should be able to retrieve information
    // about the current transaction and toplevel, to avoid the use
    // about the current transaction and toplevel, to avoid the use
    // of statics.
    // of statics.
    CdlTransaction              get_transaction() const;
    CdlTransaction              get_transaction() const;
    CdlToplevel                 get_toplevel() const;
    CdlToplevel                 get_toplevel() const;
    // active_changes and legal_values_changes get updated as the
    // active_changes and legal_values_changes get updated as the
    // transaction proceeds, so a set implementation is more
    // transaction proceeds, so a set implementation is more
    // efficient. The others get filled in during a commit operation.
    // efficient. The others get filled in during a commit operation.
    // A transaction may result in multiple conflicts for a given node
    // A transaction may result in multiple conflicts for a given node
    // being eliminated, so again a set is appropriate. For the others
    // being eliminated, so again a set is appropriate. For the others
    // there is no possibility of duplicates so a vector is better.
    // there is no possibility of duplicates so a vector is better.
    std::vector    value_changes;
    std::vector    value_changes;
    std::vector        active_changes;
    std::vector        active_changes;
    std::vector    legal_values_changes;
    std::vector    legal_values_changes;
    std::vector    value_source_changes;
    std::vector    value_source_changes;
    std::vector    new_conflicts;
    std::vector    new_conflicts;
    std::vector    new_structural_conflicts;
    std::vector    new_structural_conflicts;
    std::vector        nodes_with_resolved_conflicts;
    std::vector        nodes_with_resolved_conflicts;
    std::vector        nodes_with_resolved_structural_conflicts;
    std::vector        nodes_with_resolved_structural_conflicts;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
  protected:
  protected:
  private:
  private:
    CdlTransactionCallback(CdlTransaction);
    CdlTransactionCallback(CdlTransaction);
    CdlTransaction      transact;
    CdlTransaction      transact;
    // Illegal operation.
    // Illegal operation.
    CdlTransactionCallback();
    CdlTransactionCallback();
    enum {
    enum {
        CdlTransactionCallback_Invalid     = 0,
        CdlTransactionCallback_Invalid     = 0,
        CdlTransactionCallback_Magic       = 0x0cec3a95
        CdlTransactionCallback_Magic       = 0x0cec3a95
    } cdltransactioncallback_cookie;
    } cdltransactioncallback_cookie;
};
};
//}}}
//}}}
//{{{  CdlLocalTransaction
//{{{  CdlLocalTransaction
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A utility class to create a per-function transaction object which gets
// A utility class to create a per-function transaction object which gets
// cleaned up automatically should an exception happen.
// cleaned up automatically should an exception happen.
class CdlLocalTransaction {
class CdlLocalTransaction {
    friend class CdlTrest;
    friend class CdlTrest;
  public:
  public:
    CdlLocalTransaction(CdlToplevel toplevel) {
    CdlLocalTransaction(CdlToplevel toplevel) {
        transaction = CdlTransactionBody::make(toplevel);
        transaction = CdlTransactionBody::make(toplevel);
    }
    }
    ~CdlLocalTransaction() {
    ~CdlLocalTransaction() {
        // The destructor may get invoked during exception handling.
        // The destructor may get invoked during exception handling.
        // It is assumed that cancelling the transaction would be a
        // It is assumed that cancelling the transaction would be a
        // good thing when that happens. Normal operation should
        // good thing when that happens. Normal operation should
        // go through the body() or commit() members, which clear
        // go through the body() or commit() members, which clear
        // the transaction field.
        // the transaction field.
        // There is a slight consistency here. Normally after a
        // There is a slight consistency here. Normally after a
        // transaction commit the transaction object is still
        // transaction commit the transaction object is still
        // around. Here the transaction object get deleted. This
        // around. Here the transaction object get deleted. This
        // is unlikely to matter in practice.
        // is unlikely to matter in practice.
        if (0 != transaction) {
        if (0 != transaction) {
            transaction->cancel();
            transaction->cancel();
            delete transaction;
            delete transaction;
        }
        }
    }
    }
    CdlTransaction get() {
    CdlTransaction get() {
        return transaction;
        return transaction;
    }
    }
    void body() {
    void body() {
        transaction->body();
        transaction->body();
        delete transaction;
        delete transaction;
        transaction = 0;
        transaction = 0;
    }
    }
    void commit() {
    void commit() {
        transaction->commit();
        transaction->commit();
        delete transaction;
        delete transaction;
        transaction = 0;
        transaction = 0;
    }
    }
    void propagate() {
    void propagate() {
        transaction->propagate();
        transaction->propagate();
    }
    }
    void destroy() {
    void destroy() {
        if (0 != transaction) {
        if (0 != transaction) {
            transaction->cancel();
            transaction->cancel();
            delete transaction;
            delete transaction;
            transaction = 0;
            transaction = 0;
        }
        }
    }
    }
  private:
  private:
    CdlTransaction transaction;
    CdlTransaction transaction;
    CdlLocalTransaction();
    CdlLocalTransaction();
};
};
//}}}
//}}}
//}}}
//}}}
//{{{  Build and define information
//{{{  Build and define information
//{{{  Description
//{{{  Description
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// There are two related concepts: buildable components, and
// There are two related concepts: buildable components, and
// definable components. The former typically refers to compiling
// definable components. The former typically refers to compiling
// sources files to produce libraries, although other types of build
// sources files to produce libraries, although other types of build
// are possible. The latter refers to generating header files
// are possible. The latter refers to generating header files
// containing the current configuration data. Typically any loadable
// containing the current configuration data. Typically any loadable
// that is buildable is also definable, so that the source files can
// that is buildable is also definable, so that the source files can
// #include the appropriate generated headers and adapt to the
// #include the appropriate generated headers and adapt to the
// configuration data that way. The inverse is not true: for example
// configuration data that way. The inverse is not true: for example
// in HCDL it may be appropriate to generate a header file but there
// in HCDL it may be appropriate to generate a header file but there
// is nothing to be compiled, device drivers are software packages.
// is nothing to be compiled, device drivers are software packages.
//
//
// The relevant base classes are as follows:
// The relevant base classes are as follows:
//
//
// 1) CdlBuildable      - this object can have build-related properties.
// 1) CdlBuildable      - this object can have build-related properties.
//                        All buildables are also valuables.
//                        All buildables are also valuables.
// 2) CdlBuildLoadable  - this is a base class for loadables, providing
// 2) CdlBuildLoadable  - this is a base class for loadables, providing
//                        some extra properties that are relevant for
//                        some extra properties that are relevant for
//                        loadables that can involve builds.
//                        loadables that can involve builds.
// 3) CdlDefinable      - this object can result in #define's in a
// 3) CdlDefinable      - this object can result in #define's in a
//                        header file. All exportables are also
//                        header file. All exportables are also
//                        valuables.
//                        valuables.
// 4) CdlDefineLoadable - this is a base class for any loadables that
// 4) CdlDefineLoadable - this is a base class for any loadables that
//                        can contain buildables.
//                        can contain buildables.
//
//
// Support for both buildable and exportable components is part of the
// Support for both buildable and exportable components is part of the
// core library for now. This may change in future, depending on how
// core library for now. This may change in future, depending on how
// many CDL variants get implemented.
// many CDL variants get implemented.
//
//
// There are various properties related to building. First, the
// There are various properties related to building. First, the
// ones applicable to the CdlBuildLoadable class.
// ones applicable to the CdlBuildLoadable class.
//
//
// 1) library xyz.
// 1) library xyz.
//    This specifies the default library for anything built in this
//    This specifies the default library for anything built in this
//    loadable. If there is no library property then it defaults to
//    loadable. If there is no library property then it defaults to
//    libtarget.a (or rather to a class static that happens to be
//    libtarget.a (or rather to a class static that happens to be
//    initialized to libtarget.a)
//    initialized to libtarget.a)
//
//
// 2) include_dir .
// 2) include_dir .
//    This specifies where the loadable's exported header files should
//    This specifies where the loadable's exported header files should
//    end up. The default value is the toplevel, but e.g. the eCos
//    end up. The default value is the toplevel, but e.g. the eCos
//    kernel specifies an include_dir of cyg/kernel. Note that fixed
//    kernel specifies an include_dir of cyg/kernel. Note that fixed
//    header files are associated with buildables, not definables,
//    header files are associated with buildables, not definables,
//    the latter deal with generated header files only.
//    the latter deal with generated header files only.
//
//
// 3) include_files 
// 3) include_files 
//    The recommended directory hierarchy for non-trivial packages
//    The recommended directory hierarchy for non-trivial packages
//    involves separate subdirectories src, include, cdl, doc, and
//    involves separate subdirectories src, include, cdl, doc, and
//    test. This is too heavyweight for very simple packages where it
//    test. This is too heavyweight for very simple packages where it
//    is better to keep everything in just one directory. However that
//    is better to keep everything in just one directory. However that
//    introduces a potential conflict between public and private
//    introduces a potential conflict between public and private
//    header files, which can be resolved by the include_files
//    header files, which can be resolved by the include_files
//    property. The actual rules are:
//    property. The actual rules are:
//
//
//    a) if there an include_files property, that lists all the
//    a) if there an include_files property, that lists all the
//       headers that should be exported.
//       headers that should be exported.
//
//
//    b) else if there is an include subdirectory, it is assumed that
//    b) else if there is an include subdirectory, it is assumed that
//       all files below that should be exported.
//       all files below that should be exported.
//
//
//    c) otherwise all files matching a suitable glob pattern should
//    c) otherwise all files matching a suitable glob pattern should
//       be exported. The default pattern is *.h *.hxx *.inl, but can
//       be exported. The default pattern is *.h *.hxx *.inl, but can
//       be overwritten.
//       be overwritten.
//
//
// 4) makefile 
// 4) makefile 
//    This allows component developers to provide a GNU makefile to be
//    This allows component developers to provide a GNU makefile to be
//    used for building, rather than specify the relevant information
//    used for building, rather than specify the relevant information
//    via properties.
//    via properties.
//    NOTE: this property is ignored for now. It is roughly
//    NOTE: this property is ignored for now. It is roughly
//    equivalent to a custom build step where the command is
//    equivalent to a custom build step where the command is
//    "make -C  -f ", but in addition it is necessary to
//    "make -C  -f ", but in addition it is necessary to
//    worry about phony targets for default, clean, etc.
//    worry about phony targets for default, clean, etc.
//
//
// A DefineLoadable adds the following property:
// A DefineLoadable adds the following property:
//
//
// 1) define_header 
// 1) define_header 
//    This specifies the header file that will be generated. If this
//    This specifies the header file that will be generated. If this
//    property is absent then the library will generate a default one
//    property is absent then the library will generate a default one
//    based on the loadable's name, by discarding everything up to and
//    based on the loadable's name, by discarding everything up to and
//    including the first underscore, lowercasing the rest, and
//    including the first underscore, lowercasing the rest, and
//    appending .h. For example, CYGPKG_KERNEL would result in a
//    appending .h. For example, CYGPKG_KERNEL would result in a
//    header file kernel.h.
//    header file kernel.h.
//
//
//    Hardware packages have an implicit "define_header hardware.h"
//    Hardware packages have an implicit "define_header hardware.h"
//    property.
//    property.
//
//
// A buildable has the following properties:
// A buildable has the following properties:
//
//
// 1) compile [-library xyz]   ...
// 1) compile [-library xyz]   ...
//    This specifies one or more files that need to be compiled.
//    This specifies one or more files that need to be compiled.
//    By default the resulting object files will go into the
//    By default the resulting object files will go into the
//    current library (set via a higher-level library or
//    current library (set via a higher-level library or
//    defaulting to libtarget.a).
//    defaulting to libtarget.a).
//
//
//    Legitimate filename suffixes for compile statements are .c, .cxx
//    Legitimate filename suffixes for compile statements are .c, .cxx
//    and .S. Further suffixes may be supported in future. In the
//    and .S. Further suffixes may be supported in future. In the
//    long term we will need some external data files defining how
//    long term we will need some external data files defining how
//    the various suffixes should be handled.
//    the various suffixes should be handled.
//
//
//    Associated with every compilation are details of the compiler to
//    Associated with every compilation are details of the compiler to
//    be used and the compiler flags. For now no attempt is made
//    be used and the compiler flags. For now no attempt is made
//    to do anything interesting in this area, although there is
//    to do anything interesting in this area, although there is
//    sufficient information in the database for the needs of
//    sufficient information in the database for the needs of
//    command line tools.
//    command line tools.
//
//
//    Longer term there are complications. Packages may want some
//    Longer term there are complications. Packages may want some
//    control over the compiler flags that should be used, e.g.
//    control over the compiler flags that should be used, e.g.
//    "requires {!(flags ~= ".*-fno-rtti.*")}" to guarantee that the
//    "requires {!(flags ~= ".*-fno-rtti.*")}" to guarantee that the
//    compiler flags do not include -fno-rtti, rather useful if the
//    compiler flags do not include -fno-rtti, rather useful if the
//    package's source code depends on that language feature. Mixed
//    package's source code depends on that language feature. Mixed
//    architecture systems (e.g. ARM/Thumb) will cause problems when
//    architecture systems (e.g. ARM/Thumb) will cause problems when
//    it comes to selecting the compiler. The exact means by which
//    it comes to selecting the compiler. The exact means by which
//    all this will work is not yet clear.
//    all this will work is not yet clear.
//
//
// 2) object [-library xyz]   ...
// 2) object [-library xyz]   ...
//    This specifies one or more pre-built object files that should
//    This specifies one or more pre-built object files that should
//    go into the appropriate library.
//    go into the appropriate library.
//
//
//    The problem here is coping with different architectures, and for
//    The problem here is coping with different architectures, and for
//    many architectures it will also be necessary to worry about
//    many architectures it will also be necessary to worry about
//    multilibs. Third party component vendors are unlikely to supply
//    multilibs. Third party component vendors are unlikely to supply
//    separate object files for every supported architecture and every
//    separate object files for every supported architecture and every
//    valid multilib within those architectures, so there are
//    valid multilib within those architectures, so there are
//    constraints on the multilib-related compiler flags used for
//    constraints on the multilib-related compiler flags used for
//    building other packages and the application itself.
//    building other packages and the application itself.
//
//
//    NOTE: this property is ignored for now.
//    NOTE: this property is ignored for now.
//
//
// 3) make_object [-library xyz] [-priority pri]  
// 3) make_object [-library xyz] [-priority pri]  
//
//
//    For example:
//    For example:
//
//
//    make_object toyslock.o {
//    make_object toyslock.o {
//        toyslock.o : toyslock.y
//        toyslock.o : toyslock.y
//                yacc toyslock.y
//                yacc toyslock.y
//                $(CC) $(CFLAGS) -o toyslock.o y.tab.c
//                $(CC) $(CFLAGS) -o toyslock.o y.tab.c
//    }
//    }
//
//
//    This defines a custom build step for an object file that
//    This defines a custom build step for an object file that
//    should go into a particular directory. A makefile syntax
//    should go into a particular directory. A makefile syntax
//    is used to define the rule simply because it is likely
//    is used to define the rule simply because it is likely
//    to be familiar to package developers, and does not
//    to be familiar to package developers, and does not
//    imply that the builds will happen via a makefile.
//    imply that the builds will happen via a makefile.
//
//
//    The optional priority field indicates at which stage during
//    The optional priority field indicates at which stage during
//    the build the rule should trigger. The default value is
//    the build the rule should trigger. The default value is
//    100, which is the same as for all files specified in
//    100, which is the same as for all files specified in
//    "compile" properties. A lower value means that the object
//    "compile" properties. A lower value means that the object
//    will be generated earlier. Libraries are generated at
//    will be generated earlier. Libraries are generated at
//    priority 200, and "make" properties normally execute at
//    priority 200, and "make" properties normally execute at
//    priority 300.
//    priority 300.
//    NOTE: it is not clear yet whether supporting priorities
//    NOTE: it is not clear yet whether supporting priorities
//    in this way is a good idea, or whether the dependencies
//    in this way is a good idea, or whether the dependencies
//    information could be used instead.
//    information could be used instead.
//
//
//    Unresolved issues:
//    Unresolved issues:
//
//
//    a) what commands can be used in the build rules? There
//    a) what commands can be used in the build rules? There
//       should be a core set of supported commands, as per
//       should be a core set of supported commands, as per
//       an eCos toolchain build. It should also be possible
//       an eCos toolchain build. It should also be possible
//       for packages to provide their own host tools.
//       for packages to provide their own host tools.
//
//
//       For sourceware folks, moving away from a single toolchain
//       For sourceware folks, moving away from a single toolchain
//       tarball and expecting them to download and install
//       tarball and expecting them to download and install
//       egcs, binutils and gdb separately is actually a bad
//       egcs, binutils and gdb separately is actually a bad
//       idea in this regard, it makes it much more likely that
//       idea in this regard, it makes it much more likely that
//       some users will have an incomplete tools installation and
//       some users will have an incomplete tools installation and
//       hence that builds will fail.
//       hence that builds will fail.
//
//
//    b) there is an obvious need for variable substitution in the
//    b) there is an obvious need for variable substitution in the
//       rules, e.g. $(CC). At what stage do these variables get
//       rules, e.g. $(CC). At what stage do these variables get
//       expanded, and where does the required information live?
//       expanded, and where does the required information live?
//
//
//    c) who is responsible for header file dependency analysis?
//    c) who is responsible for header file dependency analysis?
//       Should the rules be modified automatically to do this,
//       Should the rules be modified automatically to do this,
//       or do we leave this to the package developer? It may be
//       or do we leave this to the package developer? It may be
//       very hard to do the former, but the latter will cause
//       very hard to do the former, but the latter will cause
//       problems for IDE integration.
//       problems for IDE integration.
//
//
//    d) in which directory will the rules get run? What prevents
//    d) in which directory will the rules get run? What prevents
//       filename conflicts between different packages?
//       filename conflicts between different packages?
//
//
//    NOTE: make_object is not actually required just yet, but the
//    NOTE: make_object is not actually required just yet, but the
//    issues are much the same as for the "make" property which is
//    issues are much the same as for the "make" property which is
//    required.
//    required.
//
//
// 4) make [-priority pri]  
// 4) make [-priority pri]  
//
//
//    For example:
//    For example:
//
//
//    make target.ld {
//    make target.ld {
//    target.ld : arm.ld
//    target.ld : arm.ld
//            $(CC) -E -P -xc $(CFLAGS) -o $@ $<
//            $(CC) -E -P -xc $(CFLAGS) -o $@ $<
//    }
//    }
//
//
//    This defines a custom build step for a target that is not going
//    This defines a custom build step for a target that is not going
//    to end up in a library. The main such targets at the moment are
//    to end up in a library. The main such targets at the moment are
//    the linker script, vectors.o, and extras.o, but there may well
//    the linker script, vectors.o, and extras.o, but there may well
//    be others in future.
//    be others in future.
//
//
//    The default priority for "make" properties is 300, which means
//    The default priority for "make" properties is 300, which means
//    that the build rules trigger after all normal compilations and
//    that the build rules trigger after all normal compilations and
//    after the libraries are generated. It is possible to specify
//    after the libraries are generated. It is possible to specify
//    custom build steps that should run before any compilations
//    custom build steps that should run before any compilations
//    using a priority < 100.
//    using a priority < 100.
//
//
//    Unresolved issues:
//    Unresolved issues:
//
//
//    a) what commands can be used?
//    a) what commands can be used?
//
//
//    b) variable substitution?
//    b) variable substitution?
//
//
//    c) header file dependency analysis?
//    c) header file dependency analysis?
//
//
//    d) directories and filenames?
//    d) directories and filenames?
//
//
//    e) where should the resulting files end up? Currently they can
//    e) where should the resulting files end up? Currently they can
//       all go into $(PREFIX)/lib, but in the long term we may
//       all go into $(PREFIX)/lib, but in the long term we may
//       need to be a bit more flexible.
//       need to be a bit more flexible.
//
//
// 5) build_proc 
// 5) build_proc 
//
//
//    This defines some Tcl code that should be run prior to any
//    This defines some Tcl code that should be run prior to any
//    build, for example to generate a source file. It must run
//    build, for example to generate a source file. It must run
//    within the appropriate loadable's Tcl interpreter so that
//    within the appropriate loadable's Tcl interpreter so that
//    it can query the current configuration.
//    it can query the current configuration.
//
//
//    NOTE: this property is not implemented yet.
//    NOTE: this property is not implemented yet.
//
//
//
//
// A definable has the following properties:
// A definable has the following properties:
//
//
// 1) no_define
// 1) no_define
//    Usually the library will generate either one or two #define's
//    Usually the library will generate either one or two #define's
//    for every definable, inside the current header file. This can be
//    for every definable, inside the current header file. This can be
//    suppressed by the no_define property, which is typically
//    suppressed by the no_define property, which is typically
//    accompanied by some other #define-related property such as
//    accompanied by some other #define-related property such as
//    define_proc or define.
//    define_proc or define.
//
//
// 2) define [-file ] [-format ] symbol
// 2) define [-file ] [-format ] symbol
//    This will result in an additional #define for the specified
//    This will result in an additional #define for the specified
//    symbol in the specified file. The only filenames that are valid
//    symbol in the specified file. The only filenames that are valid
//    are the loadable's current filename (as per define_header), and
//    are the loadable's current filename (as per define_header), and
//    the global header file system.h. Use of the latter should be
//    the global header file system.h. Use of the latter should be
//    avoided.
//    avoided.
//
//
//    The optional format string behaves as per the define_format
//    The optional format string behaves as per the define_format
//    property below.
//    property below.
//
//
// 3) define_format 
// 3) define_format 
//    This is only relevant for booldata or data flavors. By default
//    This is only relevant for booldata or data flavors. By default
//    two #define's will be generated (assuming the valuable is active
//    two #define's will be generated (assuming the valuable is active
//    and enabled):
//    and enabled):
//
//
//        #define  value
//        #define  value
//        #define _value
//        #define _value
//
//
//    The latter will only be generated if the resulting symbol is
//    The latter will only be generated if the resulting symbol is
//    a valid C preprocessor symbol, and is intended to allow the
//    a valid C preprocessor symbol, and is intended to allow the
//    use of #ifdef as well as #ifdef (useful if the value is
//    use of #ifdef as well as #ifdef (useful if the value is
//    non-numerical).
//    non-numerical).
//
//
//    The define_format property provides control over the first of
//    The define_format property provides control over the first of
//    these two #defines. The net result is that the #define will be
//    these two #defines. The net result is that the #define will be
//    generated by evaluating the following Tcl fragment:
//    generated by evaluating the following Tcl fragment:
//
//
//        set result "#define  [ ]"
//        set result "#define  [ ]"
//
//
//    Command and variable substitution are available if desired,
//    Command and variable substitution are available if desired,
//    but for anything that complicated the define_proc property
//    but for anything that complicated the define_proc property
//    is normally more useful.
//    is normally more useful.
//
//
//    define_format is only applicable to the default definition,
//    define_format is only applicable to the default definition,
//    so it cannot be used in conjunction with no_define. The
//    so it cannot be used in conjunction with no_define. The
//    define property supports a -format option.
//    define property supports a -format option.
//
//
// 4) define_proc 
// 4) define_proc 
//    This specifies some Tcl code that should be run when header
//    This specifies some Tcl code that should be run when header
//    file generation takes place, in addition to any #define's
//    file generation takes place, in addition to any #define's
//    generated by default or courtesy of define properties.
//    generated by default or courtesy of define properties.
//    The define_proc property is commonly used in conjunction with
//    The define_proc property is commonly used in conjunction with
//    no_define, but this is not required.
//    no_define, but this is not required.
//
//
//    There will be two channels already set up: cdl_header
//    There will be two channels already set up: cdl_header
//    for the current loadable, and cdl_system_header for system.h.
//    for the current loadable, and cdl_system_header for system.h.
//    Writing data to system.h should be avoided.
//    Writing data to system.h should be avoided.
//
//
// 5) if_define  
// 5) if_define  
//    This property provides direct support for a common programming
//    This property provides direct support for a common programming
//    paradigm. It allows direct generation of code like the
//    paradigm. It allows direct generation of code like the
//    following:
//    following:
//
//
//    #ifdef CYGSRC_TOYS_BLOCKS
//    #ifdef CYGSRC_TOYS_BLOCKS
//    # define CYGDBG_INFRA_USE_PRECONDITIONS 1
//    # define CYGDBG_INFRA_USE_PRECONDITIONS 1
//    #endif
//    #endif
//
//
//    In this case CYGSRC_TOYS_BLOCKS is the condition and
//    In this case CYGSRC_TOYS_BLOCKS is the condition and
//    CYGDBG_INFRA_USE_PRECONDITIONS is the symbol. The
//    CYGDBG_INFRA_USE_PRECONDITIONS is the symbol. The
//    #ifdef/#define sequence will be generated in addition to
//    #ifdef/#define sequence will be generated in addition to
//    any other #define's resulting from the default behaviour,
//    any other #define's resulting from the default behaviour,
//    the define property, or the define_proc property. It is
//    the define property, or the define_proc property. It is
//    not affected by no_define.
//    not affected by no_define.
//}}}
//}}}
//{{{  The build process
//{{{  The build process
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// For command-line operation the steps involved in doing a build are:
// For command-line operation the steps involved in doing a build are:
//
//
// 1) work out what needs to be built.
// 1) work out what needs to be built.
//
//
// 2) generate a build and install tree. This involves making sure that
// 2) generate a build and install tree. This involves making sure that
//    the various directories exist and are accessible.
//    the various directories exist and are accessible.
//
//
// 3) generate or update the toplevel makefile.
// 3) generate or update the toplevel makefile.
//
//
// 4) generate the configuration header files.
// 4) generate the configuration header files.
//
//
// For operation in an IDE steps (2) and (3) will be handled by
// For operation in an IDE steps (2) and (3) will be handled by
// different code.
// different code.
//
//
// There is a library call to get hold of all the build information:
// There is a library call to get hold of all the build information:
//
//
//     config->get_build_info(CdlBuildInfo &info);
//     config->get_build_info(CdlBuildInfo &info);
//
//
// This erases anything previously present in the build-info argument
// This erases anything previously present in the build-info argument
// and fills in the information appropriate to the current
// and fills in the information appropriate to the current
// configuration, essentially by walking down the list of loadables
// configuration, essentially by walking down the list of loadables
// and each loadable's list of nodes, checking for BuildLoadables
// and each loadable's list of nodes, checking for BuildLoadables
// and Buildables along the way. The BuildInfo class is defined
// and Buildables along the way. The BuildInfo class is defined
// further down.
// further down.
//
//
// An alternative library call can be used to find out about all
// An alternative library call can be used to find out about all
// possible files that need to be compiled etc., irrespective of the
// possible files that need to be compiled etc., irrespective of the
// current configuration settings. This could be useful when it
// current configuration settings. This could be useful when it
// comes to letting the user control compiler flags etc.
// comes to letting the user control compiler flags etc.
//
//
//    config->get_all_build_info(CdlBuildInfo& info);
//    config->get_all_build_info(CdlBuildInfo& info);
//
//
// There is another library call for step (4):
// There is another library call for step (4):
//
//
//    config->generate_config_headers(std::string directory)
//    config->generate_config_headers(std::string directory)
//
//
// This will create or update the header files appropriate to
// This will create or update the header files appropriate to
// the current configuration. Temporary files will be generated,
// the current configuration. Temporary files will be generated,
// diff'ed with the current version, and existing files will
// diff'ed with the current version, and existing files will
// only be modified if necessary. The directory argument
// only be modified if necessary. The directory argument
// indicates where the header files should go, i.e. it should
// indicates where the header files should go, i.e. it should
// be the equivalent of $(PREFIX)/include/pkgconf
// be the equivalent of $(PREFIX)/include/pkgconf
//
//
// This library call does not delete any files it does not
// This library call does not delete any files it does not
// recognize, that is the responsibility of higher-level code.
// recognize, that is the responsibility of higher-level code.
// It is possible to get or update a list of the files that
// It is possible to get or update a list of the files that
// will be generated:
// will be generated:
//
//
//    config->get_config_headers(std::vector& headers)
//    config->get_config_headers(std::vector& headers)
//
//
// The argument will be cleared if necessary and then filled in with
// The argument will be cleared if necessary and then filled in with
// the current set of header files. Higher level code can compare the
// the current set of header files. Higher level code can compare the
// result with the current files in the directory and take or suggest
// result with the current files in the directory and take or suggest
// remedial action.
// remedial action.
//
//
// There is also a library call which combines all four stages:
// There is also a library call which combines all four stages:
//
//
//    config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
//    config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
//
//
//
//
// The order in which the various build steps happen is important.
// The order in which the various build steps happen is important.
//
//
// 1) non-configuration headers must be copied from the component
// 1) non-configuration headers must be copied from the component
//    repository into $(PREFIX)/include. No compiles can happen
//    repository into $(PREFIX)/include. No compiles can happen
//    before this.
//    before this.
//
//
// 2) all compile properties can happen in parallel. These have an
// 2) all compile properties can happen in parallel. These have an
//    effective priority of 100.
//    effective priority of 100.
//
//
// 3) all make_object priorities can happen in parallel with
// 3) all make_object priorities can happen in parallel with
//    compiles. These have a default priority of 100, but the
//    compiles. These have a default priority of 100, but the
//    priority can be modified.
//    priority can be modified.
//
//
// 4) the generated objects and any pre-built objects should be
// 4) the generated objects and any pre-built objects should be
//    incorporated into the appropriate library. This happens
//    incorporated into the appropriate library. This happens
//    at priority 200.
//    at priority 200.
//
//
// 5) custom build steps associated with "make" properties should
// 5) custom build steps associated with "make" properties should
//    now run. These have a default priority of 300, but it is
//    now run. These have a default priority of 300, but it is
//    possible to override this.
//    possible to override this.
//
//
// Usually all source files will come from the component repository,
// Usually all source files will come from the component repository,
// which means that they are read-only. Ideally it should also be
// which means that they are read-only. Ideally it should also be
// possible for a source file to be copied into the build tree and
// possible for a source file to be copied into the build tree and
// edited there, and subsequent builds should pick up the copy rather
// edited there, and subsequent builds should pick up the copy rather
// than the original. The build data generated by libcdl will always
// than the original. The build data generated by libcdl will always
// be in the form of relative pathnames to facilitate this.
// be in the form of relative pathnames to facilitate this.
//}}}
//}}}
//{{{  CdlBuildInfo class
//{{{  CdlBuildInfo class
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Extracting the build information.
// Extracting the build information.
//
//
// libcdl.a defines the following classes related to build information.
// libcdl.a defines the following classes related to build information.
//
//
// CdlBuildInfo
// CdlBuildInfo
// CdlBuildInfo_Loadable
// CdlBuildInfo_Loadable
// CdlBuildInfo_Header
// CdlBuildInfo_Header
// CdlBuildInfo_Compile
// CdlBuildInfo_Compile
// CdlBuildInfo_Object
// CdlBuildInfo_Object
// CdlBuildInfo_MakeObject
// CdlBuildInfo_MakeObject
// CdlBuildInfo_Make
// CdlBuildInfo_Make
//
//
// The build information is organized on a per-loadable basis.
// The build information is organized on a per-loadable basis.
// Higher-level code may choose to flatten this or to keep the
// Higher-level code may choose to flatten this or to keep the
// distinction. A CdlBuildInfo object is primarily a vector of
// distinction. A CdlBuildInfo object is primarily a vector of
// CdlBuildInfo_Loadable objects. CdlBuildInfo objects can be created
// CdlBuildInfo_Loadable objects. CdlBuildInfo objects can be created
// statically.
// statically.
//
//
// In turn, each CdlBuildInfo_Loadable object is primarily a
// In turn, each CdlBuildInfo_Loadable object is primarily a
// collection of five vectors, one each for Header, Compile, Object,
// collection of five vectors, one each for Header, Compile, Object,
// MakeObject and Make.
// MakeObject and Make.
//
//
// All pathnames in these data structures will use forward slashes as
// All pathnames in these data structures will use forward slashes as
// the directory separator, irrespective of the host platform. All
// the directory separator, irrespective of the host platform. All
// pathnames will be relative.
// pathnames will be relative.
struct CdlBuildInfo_Header {
struct CdlBuildInfo_Header {
    std::string         source;         /* include/cyg_ass.h    */
    std::string         source;         /* include/cyg_ass.h    */
    std::string         destination;    /* cyg/infra/cyg_ass.h  */
    std::string         destination;    /* cyg/infra/cyg_ass.h  */
};
};
struct CdlBuildInfo_Compile {
struct CdlBuildInfo_Compile {
    std::string         library;        /* libtarget.a          */
    std::string         library;        /* libtarget.a          */
    std::string         source;         /* src/fancy.cxx        */
    std::string         source;         /* src/fancy.cxx        */
    // Compiler and cflags data may be added in future.
    // Compiler and cflags data may be added in future.
};
};
struct CdlBuildInfo_Object {
struct CdlBuildInfo_Object {
    std::string         library;        /* libtarget.a          */
    std::string         library;        /* libtarget.a          */
    std::string         object;         /* obj/hello.o          */
    std::string         object;         /* obj/hello.o          */
};
};
struct CdlBuildInfo_MakeObject {
struct CdlBuildInfo_MakeObject {
    cdl_int             priority;       /* 100                  */
    cdl_int             priority;       /* 100                  */
    std::string         library;        /* libtarget.a          */
    std::string         library;        /* libtarget.a          */
    std::string         object;         /* toyslock.o           */
    std::string         object;         /* toyslock.o           */
    std::string         deps;           /* toyslock.y           */
    std::string         deps;           /* toyslock.y           */
    /*
    /*
      It is not clear whether the deps field is actually useful in the
      It is not clear whether the deps field is actually useful in the
      context of IDE integration, but see the note about arm.inc
      context of IDE integration, but see the note about arm.inc
      above.
      above.
    */
    */
    std::string         rules;
    std::string         rules;
    /*
    /*
      A typical value for "rules" might be:
      A typical value for "rules" might be:
        yacc toyslock.y
        yacc toyslock.y
        $(CC) $(CFLAGS) -o toyslock.o y.tab.c
        $(CC) $(CFLAGS) -o toyslock.o y.tab.c
      Leading white space is not significant. Newlines are significant.
      Leading white space is not significant. Newlines are significant.
      Backslash escapes in the text will not have been processed yet.
      Backslash escapes in the text will not have been processed yet.
    */
    */
};
};
struct CdlBuildInfo_Make {
struct CdlBuildInfo_Make {
    cdl_int             priority;       /* 300                  */
    cdl_int             priority;       /* 300                  */
    std::string         target;         /* extras.o             */
    std::string         target;         /* extras.o             */
    std::string         deps;           /* libextras.a          */
    std::string         deps;           /* libextras.a          */
    std::string         rules;
    std::string         rules;
    /*
    /*
      Something like:
      Something like:
  $(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
  $(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
    */
    */
};
};
class CdlBuildInfo_Loadable {
class CdlBuildInfo_Loadable {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    std::string         name;           /* CYGPKG_INFRA         */
    std::string         name;           /* CYGPKG_INFRA         */
    std::string         directory;      /* infra/current        */
    std::string         directory;      /* infra/current        */
    std::vector            headers;
    std::vector            headers;
    std::vector           compiles;
    std::vector           compiles;
    std::vector            objects;
    std::vector            objects;
    std::vector        make_objects;
    std::vector        make_objects;
    std::vector              makes;
    std::vector              makes;
  protected:
  protected:
  private:
  private:
};
};
class CdlBuildInfo {
class CdlBuildInfo {
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    std::vector  entries;
    std::vector  entries;
  protected:
  protected:
  private:
  private:
};
};
//}}}
//}}}
//{{{  CdlBuildLoadable
//{{{  CdlBuildLoadable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// BuildLoadables are derived from Loadables and are appropriate for
// BuildLoadables are derived from Loadables and are appropriate for
// any loadables that can contain build information. There are a
// any loadables that can contain build information. There are a
// number of properties applicable at this level: makefile,
// number of properties applicable at this level: makefile,
// include_dir, include_files and library. The main interface of
// include_dir, include_files and library. The main interface of
// interest is update_build_info().
// interest is update_build_info().
//
//
// It is likely that all BuildLoadables are also Buildables, but this
// It is likely that all BuildLoadables are also Buildables, but this
// is not required.
// is not required.
class CdlBuildLoadableBody : virtual public CdlLoadableBody
class CdlBuildLoadableBody : virtual public CdlLoadableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlBuildLoadableBody();
    virtual ~CdlBuildLoadableBody();
    // This is the main way to extract information about what should
    // This is the main way to extract information about what should
    // get built. It takes into account the active and enabled states,
    // get built. It takes into account the active and enabled states,
    // as appropriate.
    // as appropriate.
    void        update_build_info(CdlBuildInfo&) const;
    void        update_build_info(CdlBuildInfo&) const;
    // An alternative which ignores the active and enabled states.
    // An alternative which ignores the active and enabled states.
    void        update_all_build_info(CdlBuildInfo&) const;
    void        update_all_build_info(CdlBuildInfo&) const;
    // Property parsers and validation code appropriate for a
    // Property parsers and validation code appropriate for a
    // build-loadable object such as makefile
    // build-loadable object such as makefile
    static void add_property_parsers(std::vector& parsers);
    static void add_property_parsers(std::vector& parsers);
    void        check_properties(CdlInterpreter);
    void        check_properties(CdlInterpreter);
    static int  parse_library(CdlInterpreter, int, const char*[]);
    static int  parse_library(CdlInterpreter, int, const char*[]);
    static int  parse_makefile(CdlInterpreter, int, const char*[]);
    static int  parse_makefile(CdlInterpreter, int, const char*[]);
    static int  parse_include_dir(CdlInterpreter, int, const char*[]);
    static int  parse_include_dir(CdlInterpreter, int, const char*[]);
    static int  parse_include_files(CdlInterpreter, int, const char*[]);
    static int  parse_include_files(CdlInterpreter, int, const char*[]);
    // By default any compiled files will go into libtarget.a, which
    // By default any compiled files will go into libtarget.a, which
    // is the default value for this variable. Individual applications may
    // is the default value for this variable. Individual applications may
    // specify an alternative default library.
    // specify an alternative default library.
    static char*        default_library_name;
    static char*        default_library_name;
    // When filling in a build_info structure the library needs to know
    // When filling in a build_info structure the library needs to know
    // what constitutes a header file. A glob pattern can be used for this.
    // what constitutes a header file. A glob pattern can be used for this.
    // NOTE: in the long term this should come out of a data file.
    // NOTE: in the long term this should come out of a data file.
    static char*        default_headers_glob_pattern;
    static char*        default_headers_glob_pattern;
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlBuildLoadableBody();
    CdlBuildLoadableBody();
  private:
  private:
    enum {
    enum {
        CdlBuildLoadableBody_Invalid    = 0,
        CdlBuildLoadableBody_Invalid    = 0,
        CdlBuildLoadableBody_Magic      = 0x55776643
        CdlBuildLoadableBody_Magic      = 0x55776643
    } cdlbuildloadablebody_cookie;
    } cdlbuildloadablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlBuildLoadableBody(const CdlBuildLoadableBody&);
    CdlBuildLoadableBody(const CdlBuildLoadableBody&);
    CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
    CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
};
};
//}}}
//}}}
//{{{  CdlBuildable
//{{{  CdlBuildable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Buildable objects can have properties such as compile and
// Buildable objects can have properties such as compile and
// make_object. These properties are not normally accessed
// make_object. These properties are not normally accessed
// directly. Instead there is a member function to update a
// directly. Instead there is a member function to update a
// CdlBuildInfo_Loadable object.
// CdlBuildInfo_Loadable object.
//
//
// The build properties for a given buildable have an effect iff
// The build properties for a given buildable have an effect iff
// that buildable is active, and in addition if the buildable is also
// that buildable is active, and in addition if the buildable is also
// a valuable then it must be enabled.
// a valuable then it must be enabled.
class CdlBuildableBody : virtual public CdlNodeBody
class CdlBuildableBody : virtual public CdlNodeBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlBuildableBody();
    virtual ~CdlBuildableBody();
    // This is the main way to extract information about what should
    // This is the main way to extract information about what should
    // get built. It takes into account the active and enabled states,
    // get built. It takes into account the active and enabled states,
    // as appropriate. The second argument indicates the default
    // as appropriate. The second argument indicates the default
    // library for the current loadable.
    // library for the current loadable.
    void        update_build_info(CdlBuildInfo_Loadable&, std::string) const;
    void        update_build_info(CdlBuildInfo_Loadable&, std::string) const;
    // An alternative which ignores the active and enabled states.
    // An alternative which ignores the active and enabled states.
    void        update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
    void        update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
    // Add property parsers and validation code appropriate for a
    // Add property parsers and validation code appropriate for a
    // buildable object such as compile and make_object
    // buildable object such as compile and make_object
    static void add_property_parsers(std::vector& parsers);
    static void add_property_parsers(std::vector& parsers);
    void        check_properties(CdlInterpreter);
    void        check_properties(CdlInterpreter);
    static int  parse_build_proc(CdlInterpreter, int, const char*[]);
    static int  parse_build_proc(CdlInterpreter, int, const char*[]);
    static int  parse_compile(CdlInterpreter, int, const char*[]);
    static int  parse_compile(CdlInterpreter, int, const char*[]);
    static int  parse_make(CdlInterpreter, int, const char*[]);
    static int  parse_make(CdlInterpreter, int, const char*[]);
    static int  parse_make_object(CdlInterpreter, int, const char*[]);
    static int  parse_make_object(CdlInterpreter, int, const char*[]);
    static int  parse_object(CdlInterpreter, int, const char*[]);
    static int  parse_object(CdlInterpreter, int, const char*[]);
    static bool split_custom_build_step(std::string /* data */, std::string& /* target */, std::string& /* deps */,
    static bool split_custom_build_step(std::string /* data */, std::string& /* target */, std::string& /* deps */,
                                        std::string& /* rules*/, std::string& /* error_msg */);
                                        std::string& /* rules*/, std::string& /* error_msg */);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlBuildableBody();
    CdlBuildableBody();
  private:
  private:
    enum {
    enum {
        CdlBuildableBody_Invalid        = 0,
        CdlBuildableBody_Invalid        = 0,
        CdlBuildableBody_Magic          = 0x16eb1c04
        CdlBuildableBody_Magic          = 0x16eb1c04
    } cdlbuildablebody_cookie;
    } cdlbuildablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlBuildableBody(const CdlBuildableBody&);
    CdlBuildableBody(const CdlBuildableBody&);
    CdlBuildableBody& operator=(const CdlBuildableBody&);
    CdlBuildableBody& operator=(const CdlBuildableBody&);
};
};
//}}}
//}}}
//{{{  CdlDefineLoadable
//{{{  CdlDefineLoadable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// DefineLoadables are derived from Loadables and are appropriate for
// DefineLoadables are derived from Loadables and are appropriate for
// any loadables that can result in generated header files containing
// any loadables that can result in generated header files containing
// configuration data. There is one applicable property,
// configuration data. There is one applicable property,
// define_header. The main interface of interest is
// define_header. The main interface of interest is
// generate_config_headers().
// generate_config_headers().
class CdlDefineLoadableBody : virtual public CdlLoadableBody
class CdlDefineLoadableBody : virtual public CdlLoadableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlDefineLoadableBody();
    virtual ~CdlDefineLoadableBody();
    // Update the header file for this loadable. The first argument
    // Update the header file for this loadable. The first argument
    // is a channel to the loadable-specific header file. The second
    // is a channel to the loadable-specific header file. The second
    // argument is a channel to the global header file.
    // argument is a channel to the global header file.
    void        generate_config_header(Tcl_Channel, Tcl_Channel) const;
    void        generate_config_header(Tcl_Channel, Tcl_Channel) const;
    // What header file should be generated for this loadable?
    // What header file should be generated for this loadable?
    virtual std::string get_config_header() const;
    virtual std::string get_config_header() const;
    // Add property parsers and validation code.
    // Add property parsers and validation code.
    static void         add_property_parsers(std::vector& parsers);
    static void         add_property_parsers(std::vector& parsers);
    void                check_properties(CdlInterpreter);
    void                check_properties(CdlInterpreter);
    static int          parse_define_header(CdlInterpreter, int, const char*[]);
    static int          parse_define_header(CdlInterpreter, int, const char*[]);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlDefineLoadableBody();
    CdlDefineLoadableBody();
  private:
  private:
    enum {
    enum {
        CdlDefineLoadableBody_Invalid   = 0,
        CdlDefineLoadableBody_Invalid   = 0,
        CdlDefineLoadableBody_Magic     = 0x7e211709
        CdlDefineLoadableBody_Magic     = 0x7e211709
    } cdldefineloadablebody_cookie;
    } cdldefineloadablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlDefineLoadableBody(const CdlDefineLoadableBody&);
    CdlDefineLoadableBody(const CdlDefineLoadableBody&);
    CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
    CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
};
};
//}}}
//}}}
//{{{  CdlDefinable
//{{{  CdlDefinable
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Definables are derived from Valuables and provide support for
// Definables are derived from Valuables and provide support for
// outputting a configuration header file.
// outputting a configuration header file.
class CdlDefinableBody : virtual public CdlValuableBody
class CdlDefinableBody : virtual public CdlValuableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlDefinableBody();
    virtual ~CdlDefinableBody();
    // Update the header file for this definable. The loadable's Tcl
    // Update the header file for this definable. The loadable's Tcl
    // interpreter will already have channels cdl_header and
    // interpreter will already have channels cdl_header and
    // cdl_system_header set up appropriately.
    // cdl_system_header set up appropriately.
    void        generate_config_header( Tcl_Channel, Tcl_Channel) const;
    void        generate_config_header( Tcl_Channel, Tcl_Channel) const;
    // Add property parsers and validation code.
    // Add property parsers and validation code.
    static void add_property_parsers(std::vector& parsers);
    static void add_property_parsers(std::vector& parsers);
    void        check_properties(CdlInterpreter);
    void        check_properties(CdlInterpreter);
    static int  parse_define(CdlInterpreter, int, const char*[]);
    static int  parse_define(CdlInterpreter, int, const char*[]);
    static int  parse_define_format(CdlInterpreter, int, const char*[]);
    static int  parse_define_format(CdlInterpreter, int, const char*[]);
    static int  parse_define_proc(CdlInterpreter, int, const char*[]);
    static int  parse_define_proc(CdlInterpreter, int, const char*[]);
    static int  parse_if_define(CdlInterpreter, int, const char*[]);
    static int  parse_if_define(CdlInterpreter, int, const char*[]);
    static int  parse_no_define(CdlInterpreter, int, const char*[]);
    static int  parse_no_define(CdlInterpreter, int, const char*[]);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  protected:
  protected:
    CdlDefinableBody();
    CdlDefinableBody();
  private:
  private:
    enum {
    enum {
        CdlDefinableBody_Invalid        = 0,
        CdlDefinableBody_Invalid        = 0,
        CdlDefinableBody_Magic          = 0x65a2c95a
        CdlDefinableBody_Magic          = 0x65a2c95a
    } cdldefinablebody_cookie;
    } cdldefinablebody_cookie;
    // Illegal operations
    // Illegal operations
    CdlDefinableBody(const CdlDefinableBody&);
    CdlDefinableBody(const CdlDefinableBody&);
    CdlDefinableBody& operator=(const CdlDefinableBody&);
    CdlDefinableBody& operator=(const CdlDefinableBody&);
};
};
//}}}
//}}}
//}}}
//}}}
//{{{  CdlDialog
//{{{  CdlDialog
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A dialog simply inherits from CdlUserVisible and provides convenient
// A dialog simply inherits from CdlUserVisible and provides convenient
// access to several dialog-specific properties.
// access to several dialog-specific properties.
class CdlDialogBody :
class CdlDialogBody :
    public virtual CdlUserVisibleBody,
    public virtual CdlUserVisibleBody,
    public virtual CdlParentableBody
    public virtual CdlParentableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlDialogBody();
    virtual ~CdlDialogBody();
    // Dialogs may be enabled or disabled globally. This affects
    // Dialogs may be enabled or disabled globally. This affects
    // CdlValuable::get_widget_hint() if the valuable has an associated
    // CdlValuable::get_widget_hint() if the valuable has an associated
    // custom dialog.
    // custom dialog.
    static void         disable_dialogs();
    static void         disable_dialogs();
    static void         enable_dialogs();
    static void         enable_dialogs();
    static bool         dialogs_are_enabled();
    static bool         dialogs_are_enabled();
    bool                has_init_proc() const;
    bool                has_init_proc() const;
    bool                has_update_proc() const;
    bool                has_update_proc() const;
    const cdl_tcl_code& get_init_proc() const;
    const cdl_tcl_code& get_init_proc() const;
    const cdl_tcl_code& get_update_proc() const;
    const cdl_tcl_code& get_update_proc() const;
    const cdl_tcl_code& get_display_proc() const;
    const cdl_tcl_code& get_display_proc() const;
    const cdl_tcl_code& get_confirm_proc() const;
    const cdl_tcl_code& get_confirm_proc() const;
    const cdl_tcl_code& get_cancel_proc() const;
    const cdl_tcl_code& get_cancel_proc() const;
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
    static int          parse_display_proc(CdlInterpreter, int, const char*[]);
    static int          parse_display_proc(CdlInterpreter, int, const char*[]);
    static int          parse_update_proc(CdlInterpreter, int, const char*[]);
    static int          parse_update_proc(CdlInterpreter, int, const char*[]);
    // Persistence support. Dialogs should just be ignored when it
    // Persistence support. Dialogs should just be ignored when it
    // comes to saving and restoring files.
    // comes to saving and restoring files.
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    // The constructor only gets invoked from inside parse_dialog()
    // The constructor only gets invoked from inside parse_dialog()
    CdlDialogBody(std::string);
    CdlDialogBody(std::string);
    static bool         dialogs_enabled;
    static bool         dialogs_enabled;
    enum {
    enum {
        CdlDialogBody_Invalid   = 0,
        CdlDialogBody_Invalid   = 0,
        CdlDialogBody_Magic     = 0x3f4df391
        CdlDialogBody_Magic     = 0x3f4df391
    } cdldialogbody_cookie;
    } cdldialogbody_cookie;
    // Illegal operations. The dialog name must be known at the time
    // Illegal operations. The dialog name must be known at the time
    // that the object is constructed.
    // that the object is constructed.
    CdlDialogBody();
    CdlDialogBody();
    CdlDialogBody(const CdlDialogBody&);
    CdlDialogBody(const CdlDialogBody&);
    CdlDialogBody& operator=(const CdlDialogBody&);
    CdlDialogBody& operator=(const CdlDialogBody&);
};
};
//}}}
//}}}
//{{{  CdlWizard
//{{{  CdlWizard
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// A wizard is very much like a dialog, just a different set of properties.
// A wizard is very much like a dialog, just a different set of properties.
class CdlWizardBody :
class CdlWizardBody :
    public virtual CdlUserVisibleBody,
    public virtual CdlUserVisibleBody,
    public virtual CdlParentableBody
    public virtual CdlParentableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    virtual ~CdlWizardBody();
    virtual ~CdlWizardBody();
    bool                has_init_proc() const;
    bool                has_init_proc() const;
    bool                has_decoration_proc() const;
    bool                has_decoration_proc() const;
    const cdl_tcl_code& get_init_proc() const;
    const cdl_tcl_code& get_init_proc() const;
    const cdl_tcl_code& get_decoration_proc() const;
    const cdl_tcl_code& get_decoration_proc() const;
    const cdl_tcl_code& get_confirm_proc() const;
    const cdl_tcl_code& get_confirm_proc() const;
    const cdl_tcl_code& get_cancel_proc() const;
    const cdl_tcl_code& get_cancel_proc() const;
    bool                has_screen(cdl_int) const;
    bool                has_screen(cdl_int) const;
    cdl_int             get_first_screen_number() const;
    cdl_int             get_first_screen_number() const;
    const cdl_tcl_code& get_first_screen() const;
    const cdl_tcl_code& get_first_screen() const;
    const cdl_tcl_code& get_screen(cdl_int) const;
    const cdl_tcl_code& get_screen(cdl_int) const;
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
    static int          parse_cancel_proc(CdlInterpreter, int, const char*[]);
    static int          parse_cancel_proc(CdlInterpreter, int, const char*[]);
    static int          parse_confirm_proc(CdlInterpreter, int, const char*[]);
    static int          parse_confirm_proc(CdlInterpreter, int, const char*[]);
    static int          parse_decoration_proc(CdlInterpreter, int, const char*[]);
    static int          parse_decoration_proc(CdlInterpreter, int, const char*[]);
    static int          parse_init_proc(CdlInterpreter, int, const char*[]);
    static int          parse_init_proc(CdlInterpreter, int, const char*[]);
    static int          parse_screen(CdlInterpreter, int, const char*[]);
    static int          parse_screen(CdlInterpreter, int, const char*[]);
    // Persistence support. Wizards should just be ignored when it
    // Persistence support. Wizards should just be ignored when it
    // comes to saving and restoring files.
    // comes to saving and restoring files.
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    // The constructor only gets invoked from inside parse_wizard().
    // The constructor only gets invoked from inside parse_wizard().
    CdlWizardBody(std::string);
    CdlWizardBody(std::string);
    // Illegal operations.
    // Illegal operations.
    CdlWizardBody();
    CdlWizardBody();
    CdlWizardBody(const CdlWizardBody&);
    CdlWizardBody(const CdlWizardBody&);
    CdlWizardBody& operator=(const CdlWizardBody&);
    CdlWizardBody& operator=(const CdlWizardBody&);
    enum {
    enum {
        CdlWizardBody_Invalid   = 0,
        CdlWizardBody_Invalid   = 0,
        CdlWizardBody_Magic     = 0x4ec1c39a
        CdlWizardBody_Magic     = 0x4ec1c39a
    } cdlwizardbody_cookie;
    } cdlwizardbody_cookie;
};
};
//}}}
//}}}
//{{{  CdlInterface class
//{{{  CdlInterface class
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Similarly for interfaces.
// Similarly for interfaces.
class CdlInterfaceBody : public virtual CdlNodeBody,
class CdlInterfaceBody : public virtual CdlNodeBody,
                         public virtual CdlUserVisibleBody,
                         public virtual CdlUserVisibleBody,
                         public virtual CdlValuableBody,
                         public virtual CdlValuableBody,
                         public virtual CdlParentableBody,
                         public virtual CdlParentableBody,
                         public virtual CdlBuildableBody,
                         public virtual CdlBuildableBody,
                         public virtual CdlDefinableBody
                         public virtual CdlDefinableBody
{
{
    friend class CdlTest;
    friend class CdlTest;
  public:
  public:
    ~CdlInterfaceBody();
    ~CdlInterfaceBody();
    void                get_implementers(std::vector&) const;
    void                get_implementers(std::vector&) const;
    void                recalculate(CdlTransaction);
    void                recalculate(CdlTransaction);
    static int          parse_interface(CdlInterpreter, int, const char*[]);
    static int          parse_interface(CdlInterpreter, int, const char*[]);
    // Persistence support. The interface data cannot sensibly be modified
    // Persistence support. The interface data cannot sensibly be modified
    // by users, it is all calculated. However it is useful to have the
    // by users, it is all calculated. However it is useful to have the
    // interface data present in the saved file so that users can examine
    // interface data present in the saved file so that users can examine
    // dependencies etc.
    // dependencies etc.
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
    static void         initialize_savefile_support(CdlToplevel);
    static void         initialize_savefile_support(CdlToplevel);
    static int          savefile_interface_command(CdlInterpreter, int, const char*[]);
    static int          savefile_interface_command(CdlInterpreter, int, const char*[]);
    bool                was_generated() const;
    bool                was_generated() const;
    virtual bool        is_modifiable() const;
    virtual bool        is_modifiable() const;
    virtual std::string get_class_name() const;
    virtual std::string get_class_name() const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
  private:
  private:
    CdlInterfaceBody(std::string, bool /* generated */);
    CdlInterfaceBody(std::string, bool /* generated */);
    bool        generated;
    bool        generated;
    enum {
    enum {
        CdlInterfaceBody_Invalid   = 0,
        CdlInterfaceBody_Invalid   = 0,
        CdlInterfaceBody_Magic     = 0x67f7fbe5
        CdlInterfaceBody_Magic     = 0x67f7fbe5
    } cdlinterfacebody_cookie;
    } cdlinterfacebody_cookie;
    CdlInterfaceBody();
    CdlInterfaceBody();
    CdlInterfaceBody(const CdlInterfaceBody&);
    CdlInterfaceBody(const CdlInterfaceBody&);
    CdlInterfaceBody& operator=(const CdlInterfaceBody&);
    CdlInterfaceBody& operator=(const CdlInterfaceBody&);
};
};
//}}}
//}}}
#endif  /* !__CDLCORE_HXX */
#endif  /* !__CDLCORE_HXX */
// EOF cdlcore.hxx
// EOF cdlcore.hxx
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.