#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
|
|
|