6 //==========================================================================
10 // The core parts of the library. This header defines aspects of
11 // CDL that are shared between software cdl, hcdl, scdl, and any
12 // future languages based on the same core technology.
14 //==========================================================================
15 //####COPYRIGHTBEGIN####
17 // ----------------------------------------------------------------------------
18 // Copyright (C) 2002 Bart Veer
19 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
21 // This file is part of the eCos host tools.
23 // This program is free software; you can redistribute it and/or modify it
24 // under the terms of the GNU General Public License as published by the Free
25 // Software Foundation; either version 2 of the License, or (at your option)
28 // This program is distributed in the hope that it will be useful, but WITHOUT
29 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
30 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
33 // You should have received a copy of the GNU General Public License along with
34 // this program; if not, write to the Free Software Foundation, Inc.,
35 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 // ----------------------------------------------------------------------------
39 //####COPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
44 // Contributors: bartv
47 //####DESCRIPTIONEND####
48 //==========================================================================
51 //{{{ Platform dependencies
53 // ----------------------------------------------------------------------------
54 // Visual C++ has the delightful feature that the source browser will generate
55 // warnings if there are any identifiers of length >= 256 characters, while at
56 // the same time use of templates in the standard C++ library can easily
57 // generate functions that long. It appears that the only way to disable the
58 // warnings is by use of a %$#@(%*&%! #pragma.
60 // Similarly, VC++ gives spurious warnings when it comes to multiple virtual
63 # pragma warning( disable: 4786 )
64 # pragma warning( disable: 4250 )
68 //{{{ nested #include's
70 // ----------------------------------------------------------------------------
71 // The libcdl API is defined using parts of the standard C++ library,
72 // including strings and various bits of STL. Therefore these headers must
73 // be #include'd here for the header file to work.
83 // <cctype> is needed in various places in the implementation.
84 // This #include should be moved to an implementation-specific
88 // Now for some eCos host-side infrastructure headers.
90 // Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
91 #include <cyg/infra/cyg_type.h>
93 // Some of the classes need to reference the cyg_assert_class_zeal enum.
94 // Also inline functions may perform assertions.
95 #include <cyg/infra/cyg_ass.h>
97 // This header file also depends on having a suitable Tcl installation
98 // Unfortunately <tcl.h> does some ugly things in the interests of
99 // portability, including defining symbols such as EXTERN when
100 // necessary, and this has to be patched up here as cleanly as possible.
102 # define __CDL_CONST_UNDEFINED
105 # define __CDL_EXTERN_UNDEFINED
108 # define __CDL_VOID_UNDEFINED
111 # define __CDL_CHAR_UNDEFINED
114 # define __CDL_SHORT_UNDEFINED
117 # define __CDL_LONG_UNDEFINED
124 #ifdef __CDL_CONST_UNDEFINED
126 # undef __CDL_CONST_UNDEFINED
128 #ifdef __CDL_EXTERN_UNDEFINED
130 # undef __CDL_EXTERN_UNDEFINED
132 #ifdef __CDL_VOID_UNDEFINED
134 # undef __CDL_VOID_UNDEFINED
136 #ifdef __CDL_CHAR_UNDEFINED
138 # undef __CDL_CHAR_UNDEFINED
140 #ifdef __CDL_SHORT_UNDEFINED
142 # undef __CDL_SHORT_UNDEFINED
144 #ifdef __CDL_LONG_UNDEFINED
146 # undef __CDL_LONG_UNDEFINED
151 //{{{ Primitive types, constants:, enums, etc.
153 // ----------------------------------------------------------------------------
154 // The CDL languages are defined in terms of arbitrary precision
155 // arithmetic. This is necessary to allow e.g. pointers to be
156 // manipulated at the CDL level on 64 bit target processors.
158 // Temporarily it is not necessary to provide this precision, so it is
159 // convenient to stick to 64 bit integers as provided by the
160 // underlying infrastructure. However the API is defined in terms of
161 // the type cdl_int, so that it will be easier in future to make the
162 // change to the correct datatype. At that point cdl_int can be
163 // redefined to be a class which supports the appropriate operators.
165 typedef cyg_int64 cdl_int;
167 // ---------------------------------------------------------------------------
168 // A common concept in the CDL language is a small amount of TCL code.
169 // This is currently stored as a simple string. Conceivably it could
170 // be byte-compiled and stored accordingly.
172 typedef std::string cdl_tcl_code;
174 // ----------------------------------------------------------------------------
177 // CDL is a declarative programming language. It does involve the
178 // manipulation of values, but such values do not necessarily
179 // correspond to hardware-level entities such as integers or double
180 // precision numbers. Hence the term "type" is avoided, "flavor"
181 // is used instead. CDL understands four different flavors.
188 // The flavor "none" is used for entities that serve only as
189 // placeholders in the hierarchy, allowing other entities to be
190 // grouped more easily.
192 // Boolean entities can be either enabled or disabled. This is the
193 // most common flavor for software configuration options, the user can
194 // either enable or disable some unit of functionality. For software
195 // packages implemented in C or C++ the implementation is obvious: iff
196 // the entity is enabled then there will be a #define, and code will
197 // check the setting using e.g. #ifdef.
199 // The flavor "data" implies some arbitrary data. Internally this will
200 // be held as a string. Other properties such as legal_values,
201 // check_proc and entry_proc can be used to constrain the
202 // actual values, for example to an integer value within a certain
205 // The flavor "booldata" combines the previous two: it means that
206 // the option can be either enabled or disabled, and if it is
207 // enabled then it must have a value as per legal_values etc.
208 // One example of this is a software package: this may be either
209 // enabled or disabled, and if it is enabled then it has a value
210 // corresponding to the version string. Another example is a hardware
211 // pin: this may or may not be connected, and if it is connected
212 // then its value identifies some other pin.
214 // An entity's flavor is not always sufficient by itself to specify
215 // how the user can manipulate it in a graphical tool. Obviously an
216 // entity of flavor "none" cannot be manipulated at all. Flavor "bool"
217 // normally implies a checkbutton, but occasionally a radiobutton will
218 // be more appropriate. "Data" says very little about the user
219 // interaction, it will be necessary to examine other properties such
220 // as legal_values to determine a sensible representation. The same
221 // goes for "BoolData", with the additional possibility that the
222 // entity may be disabled.
224 // It can be argued that three of the flavors are redundant: both Bool
225 // and BoolData could be implemented as cases of "Data" with a special
226 // legal value "disabled" (or false, or whatever); "None" could be
227 // implemented as constant "Data"; effectively CDL would manipulate
228 // all data as strings, just like e.g. all variables in Tcl, or just
229 // like all scalars in Perl. This approach is certainly tempting and
230 // might well make it easier to document the language, but in practice
231 // it would result in more verbose CDL: boolean entities really are a
232 // different beast from data entities.
234 // It can also be argued that there should be more flavors. For
235 // example there could be separate flavors for integer data, floating
236 // point data, string data, and so on. There are a number of good
237 // reasons for not doing so:
239 // 1) applying separate constraints such as legal_values allows much
240 // finer control over the actual values, for example numbers within a
241 // given range. As likely as not, a value will be constrained to
242 // something smaller than the range MININT to MAXINT (whatever those
243 // happen to be for the current target).
245 // 2) where do you stop? Do you provide separate flavors for signed
246 // vs. unsigned? Char, wchar_t, short, int, long, long long? How about
247 // the eCos data types cyg_ucount8, cyg_uint8, ... Is there support
248 // for enums? Arrays? Bitfields? Structures? Unions? C++ classes?
249 // How about other programming languages such as Ada or Java?
251 // Any attempt to implement a grand union of all data types in CDL
252 // is doomed to failure and should not be attempted. Treating
253 // everything as a string instead has proven successful in a number
254 // of languages, including Tcl and Perl.
256 // 3) for some variants of CDL, for example hardware CDL, it may not
257 // make much sense to display a value directly and allow it to be
258 // manipulated directly. The value associated with a pin entity
259 // identifies the pin to which it is connected, and typically
260 // this value will be manipulated by drag and drop rather than by
261 // typing some characters. Such a value certainly does not correspond
262 // to any machine data type.
264 // Another reason for extending the number of flavors is to provide
265 // more information. For example there could be a specialized version
266 // of the boolean flavor called "radio". This would imply a specific
267 // representation in the user interface, and it would also impose
268 // a constraint that it implicitly precludes any other radio entities
269 // within the same group. However the same information can be specified
270 // by other more general means such as requires statements.
272 enum CdlValueFlavor {
273 CdlValueFlavor_Invalid = 0,
274 CdlValueFlavor_None = 1,
275 CdlValueFlavor_Bool = 2,
276 CdlValueFlavor_BoolData = 3,
277 CdlValueFlavor_Data = 4
281 // Another important aspect of a value is where it came from. There
282 // are a number of possible sources: the default value, calculated
283 // from a default_value property; a value inferred by the inference
284 // engine; a value set by a wizard; and a value set explicitly by
285 // the user. These sources have different priorities, so for example
286 // the inference engine can safely replace a calculated default
287 // value without prompting the user, but changing a user-set value
288 // automatically is undesirable.
290 // Wizard-generated values are considered more valuable than default
291 // or inferred values (there is some user input involved), but less
292 // valuable than values set explicitly by the user: the idea is that
293 // a wizard asks fairly generic questions and makes a best guess at
294 // the correct values, which may not be precise enough for the
297 // Arguably dialogs provide a level between wizards and users, in that
298 // a dialog can theoretically manipulate several entities in one go so
299 // it is a less precise way of setting values. At this stage it does
300 // not seem worthwhile to add this distinction.
302 // The library actually maintains separate values for each source,
303 // as well as the current source which is what actually gets used.
304 // In theory it is possible for the user interface code to let
305 // the user switch between these. It is not yet clear whether this
306 // makes sense from an end user's perspective.
308 enum CdlValueSource {
309 CdlValueSource_Invalid = -1, // 0 is needed for array indexing
310 CdlValueSource_Default = 0,
311 CdlValueSource_Inferred = 1,
312 CdlValueSource_Wizard = 2,
313 CdlValueSource_User = 3,
314 CdlValueSource_Current = 4
317 // ----------------------------------------------------------------------------
320 // When there is a change to a node and there are references to that node,
321 // the referencing properties will want to be informed about this. There
322 // are various different kinds of changes, not all of which are always
323 // relevant. For example, if a CDL entity gets destroyed or unloaded then
324 // all referencing entities are likely to want to know about this, but
325 // if a container's value changes then this has no effect on a reference
326 // in e.g. a "parent" property. In some cases it is also useful to apply
327 // updates to nodes rather than properties, e.g. when a node becomes
328 // active or inactive.
330 // The generic update code is also used for initialization and finalization,
331 // i.e. when the source object itself has just been loaded or is
334 // For any particular update at most one bit set, but it is often
335 // appropriate to treat several different kinds of update with
336 // common code. Hence the enum values can be or'ed and and'ed.
339 CdlUpdate_Loaded = 0x0001, // The source has just been loaded
340 CdlUpdate_Init = 0x0002, // Second-phase of a load operation
341 CdlUpdate_Unloading = 0x0004, // The source is being unloaded
342 CdlUpdate_Created = 0x0008, // The destination has just been created
343 CdlUpdate_Destroyed = 0x0010, // The destination is being destroyed
344 CdlUpdate_ValueChange = 0x0020, // The destination's value has changed.
345 // This gets applied to nodes as well
346 CdlUpdate_ActiveChange = 0x0040 // The node has become active or inactive
349 // ----------------------------------------------------------------------------
350 // Inference engine callback.
352 // During a transaction there may be one or more invocations of the inference
353 // engine, followed by a callback which should display the current transaction
354 // status to the user and allow one or more recommended fixes to be accepted.
355 // The callback's return code indicates what should happen next. "Cancel"
356 // is pretty obvious. "Continue" may result in a commit, or it may result in
357 // another iteration.
359 enum CdlInferenceCallbackResult {
360 CdlInferenceCallbackResult_Continue = 0x01,
361 CdlInferenceCallbackResult_Cancel = 0x02
364 // ----------------------------------------------------------------------------
367 // The library can provide a hint to the GUI code as to a sensible
368 // widget to use for displaying a particular valuable. There are separate
369 // hints for the bool and data parts.
372 CdlBoolWidget_None = 0, // The boolean part is not applicable
373 CdlBoolWidget_CustomDialog = 1, // There is a valid custom dialog property
374 CdlBoolWidget_CheckButton = 2, // For simple booleans
375 CdlBoolWidget_Radio = 3, // For several mutual exclusive options,
376 // the data structure will provide a string identifier
379 enum CdlValueWidget {
380 CdlValueWidget_None = 0, // The value part is not applicable
381 CdlValueWidget_CustomDialog = 1, // There is a valid custom dialog property
382 CdlValueWidget_Loadable = 2, // Use package/version dialog
383 CdlValueWidget_EntryBox = 3, // Fallback
384 CdlValueWidget_MultilineString = 4, // For complicated strings
385 CdlValueWidget_DecimalRange = 5, // e.g. 1 to 16
386 // Could be implemented as scale, radio buttons, entry, pull-down menu,
387 // combo box, ... depending on GUI conventions and number of entries
388 CdlValueWidget_HexRange = 6, // e.g. 0x01 to 0x10
389 CdlValueWidget_OctalRange = 7, // e.g. 01 to 020
390 CdlValueWidget_DoubleRange = 8, // e.g. 0.1 to 0.2
391 CdlValueWidget_NumericSet = 9, // e.g. 1 2 4 8 16
392 // The exact nature of the numbers is irrelevant, they will only
393 // get displayed, not edited
394 // Could be implemented as radio buttons, entry widget, pull-down menu,
395 // combo box, ... depending on GUI conventions and number of entries
396 // Each entry can have its own representation
397 CdlValueWidget_StringSet = 10 // e.g. "ram", "rom"
399 // More to be added, e.g. for compiler flag handling
402 // ----------------------------------------------------------------------------
405 // The CDL input data can accept numbers in a variety of formats,
406 // for example hexadecimal as well as decimal. It is desirable to try
407 // to keep track of this formatting information where possible, so
408 // that what the user sees and what ends up in header files corresponds
409 // more closely to what is in the raw CDL data. For example, it is
410 // much easier to understand 0x7fffffff than its decimal equivalent.
412 // The information kept here is very imprecise, it provides only
413 // minimal formatting information. It is not clear yet whether this
414 // will suffice or whether something more exact is going to be needed.
417 CdlValueFormat_Default = 0,
418 CdlValueFormat_Hex = 1,
419 CdlValueFormat_Octal = 2
423 //{{{ Exception classes
425 // ----------------------------------------------------------------------------
426 // Some parts of the library make use of C++ exception handling. A number
427 // of exception classes related to this library are useful. In addition
428 // just about every part of the library can throw std::bad_alloc, but this
429 // is not checked for explicitly anywhere.
431 // This class is used for all exceptions where an error message should
432 // be displayed to the user. There is a single string message associated
433 // with the exception.
435 class CdlStringException {
436 friend class CdlTest;
439 CdlStringException(std::string message_arg) {
440 message = message_arg;
442 CdlStringException(const CdlStringException& original) {
443 message = original.message;
445 CdlStringException& operator=(const CdlStringException& original) {
446 message = original.message;
449 ~CdlStringException() {
452 const std::string& get_message() const {
457 CdlStringException();
460 // CdlInputOutputException: this gets thrown when something goes wrong during
461 // file I/O operations, e.g. a file exists but cannot be opened. The
462 // exception contains a simple string explaining the error. This string
463 // may contain multiple lines, it is intended to be written to stderr
464 // or displayed in either a text widget or a dialog box.
466 // A separate class rather than a typedef is used to avoid any possible
467 // error message confusion. Everything gets inlined so there should be
468 // no performance issues.
470 class CdlInputOutputException : public CdlStringException {
471 friend class CdlTest;
473 CdlInputOutputException(std::string message_arg) :
474 CdlStringException(message_arg) {
476 CdlInputOutputException(const CdlInputOutputException& original) :
477 CdlStringException(original) {
479 CdlInputOutputException& operator=(const CdlInputOutputException& original) {
480 (void) CdlStringException::operator=(original);
485 // This class is used when any parsing happens at the C++ level rather
486 // than at the Tcl level. The exception should be caught before it
487 // propagates through the Tcl interpreter, or the latter will end up
488 // in an inconsistent state.
490 class CdlParseException : public CdlStringException {
491 friend class CdlTest;
493 CdlParseException(std::string message_arg) :
494 CdlStringException(message_arg) {
496 CdlParseException(const CdlParseException& original) :
497 CdlStringException(original) {
499 CdlParseException& operator=(const CdlParseException& original) {
500 (void) CdlStringException::operator=(original);
505 // Evaluating an expression may fail for a variety of reasons, e.g. because
506 // some referenced entity has not been loaded into the configuration.
507 // This exception can be thrown in such cases.
509 class CdlEvalException : public CdlStringException {
510 friend class CdlTest;
512 CdlEvalException(std::string message_arg) :
513 CdlStringException(message_arg) {
515 CdlEvalException(const CdlEvalException& original) :
516 CdlStringException(original) {
518 CdlEvalException& operator=(const CdlEvalException& original) {
519 (void) CdlStringException::operator=(original);
525 //{{{ Forward declarations of the body classes
527 // ----------------------------------------------------------------------------
528 // This section provides forward declarations of the main classes in
529 // the core of the library. Each variant of CDL will define additional
530 // classes, e.g. cdl_option, but these will usually be derived from
533 // There are three types of expression in CDL:
534 // 1) ordinary expressions evaluate to a single value. The most common
535 // use is for the legal_values property.
536 // 2) list expressions evaluate to a range of values, e.g. 1 to 10,
537 // and the most common use is for the legal_values property.
538 // 3) goal expressions evaluate to either true or false and are used
539 // for e.g. requires and active_if properties.
540 class CdlExpressionBody;
541 class CdlListExpressionBody;
542 class CdlGoalExpressionBody;
544 // There are also objects for simple values, values and list values.
545 // These are expanded classes, there are no associated pointer
546 // types. It is quite likely that values need to be copied around
548 class CdlSimpleValue;
552 // Properties. The base class is CdlProperty, and there are a number
553 // of derived classes provided as standard. Additional derived classes
554 // may be added in future.
555 class CdlPropertyBody;
556 class CdlProperty_MinimalBody;
557 class CdlProperty_StringBody;
558 class CdlProperty_TclCodeBody;
559 class CdlProperty_ReferenceBody;
560 class CdlProperty_StringVectorBody;
561 class CdlProperty_ExpressionBody;
562 class CdlProperty_ListExpressionBody;
563 class CdlProperty_GoalExpressionBody;
565 // Base classes. CDL entities such as options and components derive
566 // from one or more of these, using virtual inheritance.
568 // The lowest-level class is CdlNodeBody.
570 // 1) a node usually lives in a hierarchy, below a toplevel
571 // and with a container object as the parent. However nodes
572 // can live outside a container on a temporary basis,
573 // and toplevel objects have no parent.
575 // 2) a node has a name that is unique within the hierarchy.
577 // 3) a node has a vector of properties. Actually some entities
578 // will have an empty vector, e.g. the orphans container
579 // that is internal to the library. However it is too
580 // inconvenient to have separate base classes for these.
582 // 4) nodes can be referred to by properties in other nodes.
585 // A container is a node that can contain other nodes.
586 class CdlContainerBody;
588 // A loadable object is a container whose data has come out of a CDL
589 // script of some sort. It also stores details about all entities that
590 // were loaded via this script (even if some of them were reparented)
591 // thus supporting unload operations.
592 class CdlLoadableBody;
594 // A toplevel object is a container that acts as the toplevel of
595 // a hierarchy, in other words its parent is always 0. In addition
596 // a toplevel keeps track of all the names used in the hierarchy,
597 // thus facilitating navigation.
598 class CdlToplevelBody;
600 // The remaining classes all add functionality to CdlNode, directly or
603 // A user-visible object is likely to appear in the user interface.
604 // This means it may have an alias string, a description, a
605 // documentation URL, and a gui_hint field.
606 class CdlUserVisibleBody;
608 // A valuable object has a value that can be retrieved but not
609 // necessarily modified by the user. For example the value of an
610 // interface is always calculated and users can never change it.
611 // Valuable objects have a whole bunch of associated properties
612 // including dependencies.
613 class CdlValuableBody;
615 // A parentable object has the parent property, i.e. it can
616 // be reparented to anywhere in the hierarchy
617 class CdlParentableBody;
619 // A buildable object is a valuable object that may result in
620 // something being built, typically a library in the case of
621 // software packages.
622 class CdlBuildableBody;
624 // A loadable that contains buildables
625 class CdlBuildLoadableBody;
627 // A definable object is a valuable object whose value can result
628 // in #define statements in a header file
629 class CdlDefinableBody;
631 // A loadable which can contain definables
632 class CdlDefineLoadableBody;
634 // TODO: add instantiation support
636 // Custom dialogs and wizards are provided by the core.
639 class CdlInterfaceBody;
641 // Support for Tcl interpreters is also in the core, since it is
642 // difficult to do anything CDL-related without at least one Tcl
643 // interpreter lying around.
644 class CdlInterpreterBody;
646 // The basic conflict class is part of the core library, as are a
647 // number of common derived classes for specific types of conflict.
648 class CdlConflictBody;
649 class CdlConflict_UnresolvedBody;
650 class CdlConflict_IllegalValueBody;
651 class CdlConflict_EvalExceptionBody;
652 class CdlConflict_RequiresBody;
653 class CdlConflict_DataBody;
655 // Many operations happen (or may happen) in the context of a
656 // transaction. This is necessary to keep track of the various
657 // changes that can happen: for example, changing a component's
658 // value may require other entities' default values to be
659 // recalculated; it may change some legal_values list expressions,
660 // causing current values to become invalid; it may affect
661 // "requires" properties, causing goals to become satisfied or
662 // not-satisfied; it may change the "active" state of everything
663 // below the component, not to mention any entity with an
664 // "active_if" properties, and when an entity becomes active or
665 // inactive that may in turn affect other entities.
667 // Keeping track of all of this via recursion is possible, but there
668 // are problems. If an entity is updated multiple times, no
669 // optimizations are possible. It becomes much more difficult to
670 // detect cycles. During an unload operation things can get very
671 // messy. There is no easy way to track all of the changes and report
672 // them to higher level code via a callback. There is no support
673 // for any kind of rollback. A transaction model potentially
674 // provides support for all of this, at the cost of a more
676 class CdlTransactionBody;
678 // This class is used to pass information back to the application
679 // about what has actually changed in a transaction.
680 class CdlTransactionCallback;
683 // Build info class. This is always an expanded object, but is
684 // needed here to break a circular dependency.
687 // ----------------------------------------------------------------------------
688 // Typedefs for the pointers. There are separate typedefs to cope with
689 // const vs. non-const objects. Otherwise you end up with the problem
690 // that "const CdlNode x" means that the pointer is const, not the
691 // object pointed at.
693 typedef CdlExpressionBody* CdlExpression;
694 typedef CdlListExpressionBody* CdlListExpression;
695 typedef CdlGoalExpressionBody* CdlGoalExpression;
697 typedef CdlPropertyBody* CdlProperty;
698 typedef CdlProperty_MinimalBody* CdlProperty_Minimal;
699 typedef CdlProperty_StringBody* CdlProperty_String;
700 typedef CdlProperty_TclCodeBody* CdlProperty_TclCode;
701 typedef CdlProperty_ReferenceBody* CdlProperty_Reference;
702 typedef CdlProperty_StringVectorBody* CdlProperty_StringVector;
703 typedef CdlProperty_ExpressionBody* CdlProperty_Expression;
704 typedef CdlProperty_ListExpressionBody* CdlProperty_ListExpression;
705 typedef CdlProperty_GoalExpressionBody* CdlProperty_GoalExpression;
707 typedef CdlNodeBody* CdlNode;
708 typedef CdlContainerBody* CdlContainer;
709 typedef CdlLoadableBody* CdlLoadable;
710 typedef CdlToplevelBody* CdlToplevel;
711 typedef CdlUserVisibleBody* CdlUserVisible;
712 typedef CdlValuableBody* CdlValuable;
713 typedef CdlParentableBody* CdlParentable;
714 typedef CdlBuildableBody* CdlBuildable;
715 typedef CdlBuildLoadableBody* CdlBuildLoadable;
716 typedef CdlDefinableBody* CdlDefinable;
717 typedef CdlDefineLoadableBody* CdlDefineLoadable;
719 typedef CdlDialogBody* CdlDialog;
720 typedef CdlWizardBody* CdlWizard;
721 typedef CdlInterfaceBody* CdlInterface;
723 typedef CdlInterpreterBody* CdlInterpreter;
725 typedef CdlConflictBody* CdlConflict;
726 typedef CdlConflict_UnresolvedBody* CdlConflict_Unresolved;
727 typedef CdlConflict_IllegalValueBody* CdlConflict_IllegalValue;
728 typedef CdlConflict_EvalExceptionBody* CdlConflict_EvalException;
729 typedef CdlConflict_RequiresBody* CdlConflict_Requires;
730 typedef CdlConflict_DataBody* CdlConflict_Data;
732 typedef CdlTransactionBody* CdlTransaction;
734 // ----------------------------------------------------------------------------
736 typedef const CdlExpressionBody* CdlConstExpression;
737 typedef const CdlListExpressionBody* CdlConstListExpression;
738 typedef const CdlGoalExpressionBody* CdlConstGoalExpression;
740 typedef const CdlPropertyBody* CdlConstProperty;
741 typedef const CdlProperty_MinimalBody* CdlConstProperty_Minimal;
742 typedef const CdlProperty_StringBody* CdlConstProperty_String;
743 typedef const CdlProperty_TclCodeBody* CdlConstProperty_TclCode;
744 typedef const CdlProperty_ReferenceBody* CdlConstProperty_Reference;
745 typedef const CdlProperty_StringVectorBody* CdlConstProperty_StringVector;
746 typedef const CdlProperty_ExpressionBody* CdlConstProperty_Expression;
747 typedef const CdlProperty_ListExpressionBody* CdlConstProperty_ListExpression;
748 typedef const CdlProperty_GoalExpressionBody* CdlConstProperty_GoalExpression;
750 typedef const CdlNodeBody* CdlConstNode;
751 typedef const CdlContainerBody* CdlConstContainer;
752 typedef const CdlLoadableBody* CdlConstLoadable;
753 typedef const CdlToplevelBody* CdlConstToplevel;
754 typedef const CdlUserVisibleBody* CdlConstUserVisible;
755 typedef const CdlValuableBody* CdlConstValuable;
756 typedef const CdlParentableBody* CdlConstParentable;
757 typedef const CdlBuildableBody* CdlConstBuildable;
758 typedef const CdlBuildLoadableBody* CdlConstBuildLoadable;
759 typedef const CdlDefinableBody* CdlConstDefinable;
760 typedef const CdlDefineLoadableBody* CdlConstDefineLoadable;
762 typedef const CdlDialogBody* CdlConstDialog;
763 typedef const CdlWizardBody* CdlConstWizard;
764 typedef const CdlInterfaceBody* CdlConstInterface;
766 typedef const CdlInterpreterBody* CdlConstInterpreter;
768 typedef const CdlConflictBody* CdlConstConflict;
769 typedef const CdlConflict_UnresolvedBody* CdlConstConflict_Unresolved;
770 typedef const CdlConflict_IllegalValueBody* CdlConstConflict_IllegalValue;
771 typedef const CdlConflict_EvalExceptionBody* CdlConstConflict_EvalException;
772 typedef const CdlConflict_RequiresBody* CdlConstConflict_Requires;
773 typedef const CdlConflict_DataBody* CdlConstConflict_Data;
775 typedef const CdlTransactionBody* CdlConstTransaction;
778 //{{{ Miscellaneous types etc.
780 // ----------------------------------------------------------------------------
781 // This section is used for data types, function prototypes, etc. which could
782 // not be defined until after the main CDL classes and handles.
784 // This typedef is used for error and warning reporting functions.
785 // Typically such a function pointer will be passed when the library
786 // is asked to perform any non-trivial parsing operation, e.g. loading
789 // If the error is fatal then this callback function should raise
790 // a CdlParseException.
791 typedef void (*CdlDiagnosticFnPtr)(std::string);
793 // ----------------------------------------------------------------------------
794 // This function is used for update handler. Whenever there is a change
795 // to CDL entity (it has just been loaded, or its value has changed, or
796 // whatever) this can affect other CDL entities that reference it.
797 // All such references occur via properties, and there should be
798 // update handlers associated with those properties.
800 // Update handlers are also invoked for initialization and finalization
801 // operations, i.e. when the source object itself has just been loaded
802 // or is in the process of being unloaded.
804 // The arguments to an update handler are:
805 // 1) the transaction in which the operation takes place
806 // 2) the source object containing the reference
807 // 3) the source property containing the reference
808 // 4) the destination object. This may be 0 for some update
810 // 5) an indication of the change that has happened. This should
811 // be a CdlUpdate value.
812 typedef void (*CdlUpdateHandler)(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
814 // ----------------------------------------------------------------------------
815 // This function is also used for transactions. Typically during a
816 // transaction there will be one or more invocations of the inference engine,
817 // with callbacks in between to allow one or more of the recommended
818 // changes to be undone.
819 typedef CdlInferenceCallbackResult (*CdlInferenceCallback)(CdlTransaction);
821 // ----------------------------------------------------------------------------
822 // The TCL API and C++ do not always mesh cleanly, for example a lot
823 // happens in terms of ClientData which is a void* pointer. To avoid
824 // too many casts all over the place libcdl provides a CdlInterpreter
825 // class and the following alternative to Tcl_CmdProc*. A single
826 // function will be used for the TCL command: its ClientData will be
827 // the CdlInterpreterCommand, and the CdlInterpreter is accessible via
828 // AssocData. This does result in some overheads, but none of these
829 // should be in performance-critical code.
830 typedef int (*CdlInterpreterCommand)(CdlInterpreter, int, const char*[]);
832 // ----------------------------------------------------------------------------
833 // In the libcdl world it is often convenient to swap whole sets of
834 // commands in and out. For example when executing the body of a
835 // cdl_component it is desirable to swap in commands for all the
836 // properties that make sense in a component and swap out all the
837 // commands that made sense in a higher level. It is assumed that none
838 // of the commands being swapped in or out are built-ins. Achieving
839 // this involves a vector of this simple utility structure.
840 class CdlInterpreterCommandEntry {
843 CdlInterpreterCommand command;
845 CdlInterpreterCommandEntry() : name(""), command(0) {}
846 CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
847 : name(name_arg), command(command_arg)
850 CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
851 : name(name_arg), command(command_arg)
854 ~CdlInterpreterCommandEntry()
861 // ----------------------------------------------------------------------------
862 // Persistence support.
863 // Some applications want to be able to store additional information
864 // in savefiles, and essentially this involves extra commands that
865 // get executed when the savefile is executed. It is possible that
866 // the application reading back the savefile does not understand
867 // the same set of commands as the application that wrote back the
868 // data, so the library tries hard not to lose data.
870 // The CdlSaveCallback function typedef is used when installing
871 // an application-specific savefile command. The first argument
872 // indicates the node for which the callback is being invoked:
873 // this may be the entire toplevel, or just an option, or whatever.
875 // The CdlSavefileCommand structure keeps track of the command,
876 // the save callback if any (non-zero only for application-specific
877 // data, zero implies that the command is handled by the lirary).
878 // The load command is invoked when reading in a savefile and the
879 // appropriate command is executed: unrecognised commands will be
880 // processed by CdlToplevelBody::savefile_handle_unknown().
882 typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
884 struct CdlSavefileCommand {
886 CdlSaveCallback save_callback;
887 CdlInterpreterCommand load_command;
890 // ----------------------------------------------------------------------------
892 // This structure provides widget hint information for a CdlValuable.
893 // There are separate hints for the bool and data parts, and possibly
894 // some additional data such as a string identifying the set of
895 // items in a radio button.
896 struct CdlWidgetHint {
897 CdlBoolWidget bool_widget;
898 CdlValueWidget value_widget;
899 std::string radio_button_interface;
903 //{{{ Memory leak detection
905 // ----------------------------------------------------------------------------
906 // Provide some macros that are useful for detecting memory leaks. Basically
907 // there is a static counter for every class, which gets incremented by the
908 // constructor(s) and decremented by the destructor. Memory leak detection
909 // is currently enabled if tracing is enabled. It would be possible to use
910 // another configure-time option, but the overheads of tracing are likely
911 // to dwarf the overheads of memory leak detection.
913 // For now the memleak counters are always present, even in non-debug
914 // versions. The overhead is sufficiently small that it can be
915 // ignored.There is control over whether or not the counters get
916 // updated in the constructor or destructor. Otherwise there would be problems
917 // with whether or not there should be a semicolon at the end of the
918 // CYGDBG_DECLARE_MEMLEAK_COUNTER() macro definition.
920 #define CYGDBG_DECLARE_MEMLEAK_COUNTER() static int memleak_counter
921 #define CYGDBG_DEFINE_MEMLEAK_COUNTER(class) int class::memleak_counter = 0
922 #define CYGDBG_GET_MEMLEAK_COUNTER(class) class::memleak_counter
924 #ifdef CYGDBG_USE_TRACING
926 #define CYGDBG_MEMLEAK_CONSTRUCTOR() this->memleak_counter++;
927 #define CYGDBG_MEMLEAK_DESTRUCTOR() this->memleak_counter--;
928 #define CYGDBG_MEMLEAK_CHECKTHIS() if (this->memleak_counter < 0) { return false; }
932 #define CYGDBG_MEMLEAK_CONSTRUCTOR()
933 #define CYGDBG_MEMLEAK_DESTRUCTOR()
934 #define CYGDBG_MEMLEAK_CHECKTHIS()
942 // ---------------------------------------------------------------------------
943 // The sole purpose of this class is to provide some utility functions with
944 // reasonable namespace protection, without requiring that the compiler
945 // implements namespaces.
951 static bool is_valid_value_flavor(CdlValueFlavor);
952 static bool is_valid_value_source(CdlValueSource);
954 static bool is_valid_cdl_name(const std::string&);
955 static bool is_valid_c_preprocessor_symbol(const std::string&);
957 static bool string_to_integer(std::string, cdl_int&);
958 static bool string_to_double(std::string, double&);
959 static bool string_to_bool(std::string, bool&);
960 static void integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default);
961 static std::string integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default);
962 static void double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default);
963 static std::string double_to_string(double, CdlValueFormat = CdlValueFormat_Default);
964 static void bool_to_string(bool, std::string&);
965 static std::string bool_to_string(bool);
966 static void integer_to_double(cdl_int, double&);
967 static double integer_to_double(cdl_int);
968 static bool double_to_integer(double, cdl_int&);
970 static bool string_to_flavor(std::string, CdlValueFlavor&);
971 static bool flavor_to_string(CdlValueFlavor, std::string&);
972 static bool string_to_source(std::string, CdlValueSource&);
973 static bool source_to_string(CdlValueSource, std::string&);
975 static std::string get_library_version();
976 static void set_interactive(bool = true);
977 static bool is_interactive();
979 static bool truth() { return true; }
980 static bool falsehood() { return false; }
982 // return values are -1,0,1 just like strcmp(). The most recent
983 // version is the smallest.
984 static int compare_versions(std::string, std::string);
986 // Also provide an STL-friendly comparison class
989 bool operator()(const std::string& v1, const std::string& v2) const {
990 return Cdl::compare_versions(v1,v2) < 0;
994 // Split a version string into major, minor and release numbers.
995 static void split_version_string(const std::string&, std::string& /* major */,
996 std::string& /* minor */, std::string& /* release */);
998 // It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL
999 // and turn it into a short form, i.e. kernel.
1000 static std::string get_short_form(const std::string&);
1003 static bool interactive;
1007 //{{{ CdlInterpreter class
1009 // ----------------------------------------------------------------------------
1010 // libcdl requires access to a Tcl interpreter. For now the standard
1011 // interpreter is used. In the long run it may be better to use a
1012 // custom parser in places, if only to improve the diagnostics messages
1015 // Consider the case of software CDL (other CDL variants will have
1016 // similar requirements). A Tcl interpreter is needed to read in the
1017 // data for a given package. It will also be needed at various stages
1018 // when the data is being manipulated, e.g. to display a custom dialog
1019 // or to execute e.g. a check_proc or a define_proc. Each package
1020 // should run in its own safe interpreter with limited capabilities:
1021 // file I/O is limited to read-only, but read-write in the build and
1022 // install trees; network I/O is out of the question, at least until
1023 // appropriate security support is added to the CDL language itself.
1024 // However the interpreter should be extended with additional commands
1025 // like cdl_get and cdl_set to access the configuration data.
1027 // For security and robustness reasons it is desirable to have
1028 // separate interpreters for the various packages. This leads to the
1029 // concept of a master interpreter for the entire configuration, and a
1030 // group of slave interpreters, one per package. In this model it
1031 // is convenient to have the configuration and package entities
1032 // associated directly with the interpreter. Note that a single
1033 // application may have several configurations loaded in memory,
1034 // so there may be several master interpreters.
1036 // Some applications will want to support the graphical side of CDL,
1037 // i.e. custom dialogs and wizards. This means linking in Tk, not to
1038 // mention X11 (or the Windows equivalents), and making some/all of
1039 // the Tk commands available to the safe interpreter. Arguably
1040 // commands like toplevel should always be disabled. Not all clients
1041 // of libcdl will want the overheads of linking with Tk and X, so this
1042 // has to be made optional.
1044 // The approach taken is as follows:
1046 // 1) there is a class CdlInterpreter which provides access to Tcl
1047 // interpreters. Amongst other things it takes care of converting
1048 // between C and C++ strings.
1050 // 2) every toplevel needs its own CdlInterpreter. The application
1051 // code should supply this interpreter itself when the toplevel
1052 // is instantiated, allowing it to decide whether or not Tk should
1055 // 3) each loadable gets its own safe slave interpreter, derived from
1056 // the toplevel's interpreter.
1057 // NOTE: initially the slave interpreters are not actually safe. It
1058 // is not clear in the long term to what extent per-loadable
1059 // interpreters need to be sandboxes, there are issues such as
1060 // doing the equivalent of autoconf tests.
1062 // Tcl 8.4 involved various incompatible API changes related to
1063 // const vs. non-const data. #define'ing USE_NON_CONST or
1064 // USE_COMPAT_CONST avoids some of the problems, but does not
1065 // help much for C++.
1066 #if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
1067 # define CDL_TCL_CONST_CAST(type,var) (var)
1069 # define CDL_TCL_CONST_CAST(type,var) const_cast<type>(var)
1072 class CdlInterpreterBody
1074 friend class CdlTest;
1078 CYGDBG_DECLARE_MEMLEAK_COUNTER();
1080 // This is how a top-level (i.e. per-toplevel) interpreter
1081 // should get created.
1082 static CdlInterpreter make(Tcl_Interp* = 0);
1084 // Create a slave interpreter for reading in the data in e.g. a
1086 CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
1088 // Make the interpreter safe, a one-way operation.
1091 // The destructor is public.
1092 virtual ~CdlInterpreterBody();
1094 // Add or remove commands from an interpreter. This provides
1095 // a more C++-friendly implementation of Tcl's
1096 // CreateCommand() and DeleteCommand().
1097 void add_command(std::string, CdlInterpreterCommand);
1098 void remove_command(std::string);
1100 // In the libcdl world it is also convenient to swap whole sets of
1101 // commands in and out. This is achieved by push and pop operations.
1102 // push returns the old set (0 at the toplevel). pop restores
1104 std::vector<CdlInterpreterCommandEntry>* push_commands(std::vector<CdlInterpreterCommandEntry>&);
1105 void pop_commands(std::vector<CdlInterpreterCommandEntry>*);
1106 std::vector<CdlInterpreterCommandEntry>* get_pushed_commands() const;
1108 // Similarly, allow variables to be set, unset and queried
1109 void set_variable(std::string, std::string);
1110 void unset_variable(std::string);
1111 std::string get_variable(std::string);
1113 // FIXME: add support for variable traces. These are needed
1114 // for cdl_value and similar utilities.
1116 // Provide hooks into the AssocData() facilities associated with
1117 // Tcl interpreters. This makes it possible to store arbitrary
1118 // data with an interpreter, e.g. to keep track of current state.
1119 void set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0);
1120 void delete_assoc_data(const char*);
1121 ClientData get_assoc_data(const char*);
1123 // Evaluate a string as Tcl code. The return value comes from Tcl, e.g.
1124 // TCL_OK or TCL_ERROR. There are variants depending on whether or not
1125 // the result string is of interest.
1126 int eval(std::string);
1127 int eval(std::string, std::string&);
1129 // Ditto for any Tcl code that comes from CDL files
1130 int eval_cdl_code(const cdl_tcl_code);
1131 int eval_cdl_code(const cdl_tcl_code, std::string&);
1133 // And support for evaluating an entire file
1134 int eval_file(std::string);
1135 int eval_file(std::string, std::string&);
1137 // For use by commands implemented in C++, a way of setting the result
1138 void set_result(std::string);
1140 // And a utility to get the result as well.
1141 std::string get_result();
1143 // Was the result set by the Tcl interpreter or by libcdl?
1144 bool result_set_by_cdl();
1146 // A utility to quote data that is going to end up in a TCL script.
1147 static std::string quote(std::string);
1149 // Turn some multiline data into a comment.
1150 static std::string multiline_comment(const std::string&, int, int = 0);
1152 // Add some data to a comment, allowing for newlines if necessary
1153 static std::string extend_comment(const std::string&, int, int = 0);
1155 // Write some data to a savefile, throwing an exception on error
1156 void write_data(Tcl_Channel, std::string);
1158 // File-related utilities.
1159 void locate_subdirs(std::string, std::vector<std::string>&);
1160 void locate_all_subdirs(std::string, std::vector<std::string>&);
1161 void locate_files(std::string, std::vector<std::string>&);
1162 void locate_all_files(std::string, std::vector<std::string>&);
1163 bool is_directory(std::string);
1164 bool is_file(std::string);
1166 // When parsing a CDL script it is convenient to keep track of
1167 // a number of items:
1169 // 1) the toplevel, e.g. the entire configuration
1170 // 2) the loadable, e.g. the current package
1171 // 3) the parent of whatever is being processed at the moment
1172 // 4) the entity, i.e. the thingamajig that is being processed.
1173 // 5) the current file
1174 // 6) an error reporting function
1176 // This gives the various commands embedded in the Tcl interpreter
1177 // enough information to do their job. Additional information can
1178 // be provided via assoc_data()
1180 // There should be only one call to set_toplevel(), for the
1181 // master interpreter. All slaves inherit this, and the toplevel
1182 // cannot be changed again.
1184 // The loadable field is filled in via make_slave()
1186 // For some members push and pop functions are more appropriate
1188 CdlToplevel get_toplevel() const;
1189 CdlLoadable get_loadable() const;
1190 CdlContainer get_container() const;
1191 CdlNode get_node() const;
1192 std::string get_context() const;
1193 CdlDiagnosticFnPtr get_error_fn_ptr() const;
1194 CdlDiagnosticFnPtr get_warning_fn_ptr() const;
1195 CdlTransaction get_transaction() const;
1196 void set_toplevel(CdlToplevel);
1197 void set_transaction(CdlTransaction);
1198 CdlContainer push_container(CdlContainer);
1199 void pop_container(CdlContainer);
1200 CdlNode push_node(CdlNode);
1201 void pop_node(CdlNode);
1202 std::string push_context(std::string);
1203 void pop_context(std::string);
1204 CdlDiagnosticFnPtr push_error_fn_ptr(CdlDiagnosticFnPtr);
1205 void pop_error_fn_ptr(CdlDiagnosticFnPtr);
1206 CdlDiagnosticFnPtr push_warning_fn_ptr(CdlDiagnosticFnPtr);
1207 void pop_warning_fn_ptr(CdlDiagnosticFnPtr);
1209 // Provide utility classes for common push/pop combinations. The
1210 // push happens during the constructor, the pop during the
1211 // destructor. This can simplify some code, especially when
1212 // exceptions may get thrown.
1215 DiagSupport(CdlInterpreter interp_arg, CdlDiagnosticFnPtr error_fn_arg, CdlDiagnosticFnPtr warn_fn_arg) {
1216 interp = interp_arg;
1217 saved_error_fn = interp->push_error_fn_ptr(error_fn_arg);
1218 saved_warn_fn = interp->push_warning_fn_ptr(warn_fn_arg);
1221 interp->pop_error_fn_ptr(saved_error_fn);
1222 interp->pop_warning_fn_ptr(saved_warn_fn);
1227 CdlInterpreter interp;
1228 CdlDiagnosticFnPtr saved_error_fn;
1229 CdlDiagnosticFnPtr saved_warn_fn;
1231 class ContextSupport {
1233 ContextSupport(CdlInterpreter interp_arg, std::string context) {
1234 interp = interp_arg;
1235 saved_context = interp->push_context(context);
1238 interp->pop_context(saved_context);
1242 CdlInterpreter interp;
1243 std::string saved_context;
1245 class ContainerSupport {
1247 ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
1248 interp = interp_arg;
1249 saved_container = interp->push_container(container);
1251 ~ContainerSupport() {
1252 interp->pop_container(saved_container);
1256 CdlInterpreter interp;
1257 CdlContainer saved_container;
1261 NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
1262 interp = interp_arg;
1263 saved_node = interp->push_node(node);
1266 interp->pop_node(saved_node);
1270 CdlInterpreter interp;
1273 class CommandSupport {
1275 CommandSupport(CdlInterpreter interp_arg, std::vector<CdlInterpreterCommandEntry>& commands) {
1276 interp = interp_arg;
1277 saved_commands = interp->push_commands(commands);
1279 CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
1281 for (i = 0; 0 != commands[i].command; i++) {
1282 new_commands.push_back(commands[i]);
1284 interp = interp_arg;
1285 saved_commands = interp->push_commands(new_commands);
1288 interp->pop_commands(saved_commands);
1293 CdlInterpreter interp;
1294 std::vector<CdlInterpreterCommandEntry>* saved_commands;
1295 std::vector<CdlInterpreterCommandEntry> new_commands;
1298 // Similar utility classes for variables and assoc data.
1299 class VariableSupport {
1301 VariableSupport(CdlInterpreter interp_arg, std::string varname_arg, std::string data) {
1302 interp = interp_arg;
1303 varname = varname_arg;
1304 interp->set_variable(varname, data);
1306 ~VariableSupport() {
1307 interp->unset_variable(varname);
1311 CdlInterpreter interp;
1312 std::string varname;
1314 class AssocSupport {
1316 AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
1317 interp = interp_arg;
1319 interp->set_assoc_data(name, data, del_proc);
1322 interp->delete_assoc_data(name);
1326 CdlInterpreter interp;
1330 // Some command implementations may want to access other Tcl library
1331 // routines such as Tcl_SplitList(). This requires convenient access
1332 // to the underlying Tcl interpreter.
1333 Tcl_Interp* get_tcl_interpreter() const;
1335 // For use by the assertion macros.
1336 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
1339 // This is the Tcl command proc that gets registered for all
1340 // CdlInterpreterCommand instances.
1341 static int tcl_command_proc(ClientData, Tcl_Interp*, int, const char*[]);
1343 // This key is used to access the CdlInterpreter assoc data.
1344 static char* cdlinterpreter_assoc_data_key;
1346 // Do not allow static instances of a Cdl interpreter. There are too
1347 // many possible failure conditions. Cdl interpreters can only be
1348 // created dynamically via make(), which will invoke this.
1349 CdlInterpreterBody(Tcl_Interp*);
1351 // Default constructor, copy constructor and assignment are illegal
1352 CdlInterpreterBody();
1353 CdlInterpreterBody(const CdlInterpreterBody&);
1354 CdlInterpreterBody& operator=(const CdlInterpreterBody&);
1357 Tcl_Interp* tcl_interp; // The underlying Tcl interpreter
1358 bool owns_interp; // Was the Tcl interpreter created by the library?
1359 std::vector<CdlInterpreter> slaves; // All slave interpreters
1360 CdlInterpreter parent; // Or else the parent
1361 CdlToplevel toplevel; // Data that gets used during the parsing process
1362 CdlTransaction transaction;
1363 CdlLoadable loadable;
1364 CdlContainer container;
1366 std::string context;
1367 CdlDiagnosticFnPtr error_fn_ptr;
1368 CdlDiagnosticFnPtr warning_fn_ptr;
1371 std::vector<CdlInterpreterCommandEntry>* current_commands; // for push() and pop()
1374 CdlInterpreterBody_Invalid = 0,
1375 CdlInterpreterBody_Magic = 0x0be67689
1376 } cdlinterpreterbody_cookie;
1380 //{{{ CdlReference/Referrer classes
1382 // ---------------------------------------------------------------------------
1383 // CDL objects are organised primarily in a tree hierarchy. For
1384 // example a package contains components, components contain options,
1385 // and so on. The tree hierarchy tends to change rather infrequently,
1386 // so it makes sense to have a quick way of navigating between
1387 // entities without continuously having to do hash-table lookups. In
1388 // addition it is very desirable to make the connectivity
1389 // bidirectional: if a "requires" property in option A references
1390 // option B then it would be useful to have a link back to A from B;
1391 // that way, if the value of B changes it is a lot easier to keep
1392 // things up to date.
1394 // Terminology: the entity which contains the reference, e.g. a
1395 // "requires" property, is the source. The relevant property is the
1396 // "source property". The entity pointed at is the destination.
1398 // Unfortunately there may be connections between CDL entities outside
1399 // the tree hierarchy. In particular any property can contain one or
1400 // more references to packages, components, options, wizards, or
1401 // whatever. Often these references will be to options etc. within the
1402 // same package, but some references will go to other packages. There
1403 // may even be references to other configurations: for example a board
1404 // may contain both an ordinary processor and a DSP; these two need
1405 // their own configurations; however a package running on the DSP may
1406 // need to interact with a package running on the processor, and vice
1409 // Also, a reference may occur inside an object that is not in the
1410 // hierarchy. For example CDL expressions may get evaluated inside Tcl
1411 // code rather than as part of a property. Such expressions may still
1412 // contain references to entities in the current configuration.
1414 // References may not be resolved. When reading in a CDL script there
1415 // may be forward references. A reference may involve another package
1416 // that has not yet been loaded, which is a conflict.
1418 // Using simple pointers to store these connections is a bad idea. It
1419 // makes it a lot harder to figure out what is connected to what, and
1420 // it introduces horrible consistency problems when packages get
1421 // loaded and unloaded. Instead libCDL provides a CdlReference class.
1422 // Whenever a CdlProperty contains a reference to some other CDL
1423 // entity there should be a CdlReference object corresponding to this.
1424 // The reverse direction is handled via a CdlReferrer object.
1426 // A CdlReference object can be either bound or unbound. By default it
1427 // is unbound, containing only a string. It can then be bound via a
1428 // member function, examined, and unbound again as required. Creating
1429 // a binding automatically creates a CdlReferrer entry in the target
1430 // object, thus avoiding any risk of inconsistencies.
1432 // The CdlReference class should not be used outside the hierarchy,
1433 // since every bound reference must have a referrer object pointing
1434 // back, and this link back can only be valid within the hierarchy.
1435 // Temporary CdlReference objects are useful during the construction
1438 // It is possible that a given property (e.g. a complicated "requires"
1439 // expression) has multiple references to another entity. Each of
1440 // these involves a separate CdlReference/CdlReferrer pair.
1442 // ----------------------------------------------------------------------------
1443 // The actual CdlReference class.
1445 class CdlReference {
1447 friend class CdlTest;
1449 // CdlReferrer must be a friend so that when a package gets unloaded
1450 // it can clean up all references to it.
1451 friend class CdlReferrer;
1455 // The default constructor should not normally be used, instead
1456 // a string should be supplied. However there are vectors of
1457 // reference objects...
1460 // The main constructor supplies the name of the referenced
1461 // entity. The resulting object will be unbound.
1462 CdlReference(const std::string);
1464 // The copy constructor is legal for unbound objects only.
1465 CdlReference(const CdlReference&);
1467 // The assignment operator is needed for STL operations.
1468 // Again it only makes sense of unbound objects.
1469 CdlReference& operator=(const CdlReference&);
1471 // The destructor is only valid for unbound objects. All references
1472 // should be unbound before an entity can be destroyed.
1475 // Access the various fields.
1476 void set_destination_name(const std::string);
1477 const std::string& get_destination_name() const;
1478 CdlNode get_destination() const;
1480 // Binding a reference. Obviously this can only be used when the
1481 // reference is still unbound. When doing the binding it is
1482 // necessary to know:
1483 // (1) the object containing the reference.
1484 // (2) the specific property that contains the reference.
1485 // (3) the object being referred to.
1486 // Binding a reference results in a new referrer entry in the
1488 void bind(CdlNode, CdlProperty, CdlNode);
1490 // Unbinding a reference. Typically this only happens when the
1491 // destination is unloaded. The arguments provide the source and
1492 // the source property.
1493 void unbind(CdlNode, CdlProperty);
1495 // This is used by the ASSERT_CLASS() and ASSERT_THIS() macros.
1496 bool check_this(cyg_assert_class_zeal cyg_quick) const;
1497 CYGDBG_DECLARE_MEMLEAK_COUNTER();
1503 // The data fields. The name is usually filled in by the
1504 // constructor. The destination defaults to zero for an unbound
1505 // object and gets filled in by the bind() operation.
1506 std::string dest_name;
1510 CdlReference_Invalid = 0,
1511 CdlReference_Magic = 0x3f908608
1512 } cdlreference_cookie;
1515 // ----------------------------------------------------------------------------
1516 // The CdlNode class (and hence just about everything) contains a
1517 // vector of CdlReferrer objects. This keeps track of all entities
1518 // that refer to this one, so if the value associated with this
1519 // changes it is possible to work out the impact of this on all
1520 // entities that rely on this value.
1522 // Arguably this should work in terms of CdlValuable objects rather
1523 // than CdlNode objects. However it is convenient to use references
1524 // for the connection between e.g. an option and a dialog, where
1525 // there is no value involved. The reverse connection is of little
1526 // use in this circumstance.
1528 // CdlReferrer objects are rarely accessed directly. Instead they will
1529 // be filled in during a CdlReference::bind() operation and erased
1530 // during a CdlReference::unbind() operation. The only operations that
1531 // should be public allow access to the contained data.
1535 friend class CdlTest;
1537 // CdlReference::bind() and unbind() have direct access to the
1538 // members, since these two functions are really responsible for
1539 // creating and destroying referrer objects.
1540 friend class CdlReference;
1544 // The default constructor, copy constructor and assignment
1545 // operator are all public to avoid problems with having vectors
1546 // of referrer objects. Similarly the destructor is public.
1547 // In practice updates actually happen as a consequence of
1548 // CdlReference::bind() and CdlReference::unbind().
1550 CdlReferrer(const CdlReferrer&);
1551 CdlReferrer& operator=(const CdlReferrer&);
1554 CdlNode get_source() const;
1555 CdlProperty get_source_property() const;
1556 void update(CdlTransaction, CdlNode, CdlUpdate);
1557 bool check_this(cyg_assert_class_zeal=cyg_quick) const;
1558 CYGDBG_DECLARE_MEMLEAK_COUNTER();
1563 CdlProperty source_property;
1566 CdlReferrer_Invalid = 0,
1567 CdlReferrer_Magic = 0x70e1fc37
1568 } cdlreferrer_cookie;
1572 //{{{ Value and Expression classes
1574 //{{{ CdlEvalContext
1576 // ----------------------------------------------------------------------------
1577 // Expression evaluation always happens within a certain context.
1578 // This may involve a transaction. Usually it involves a node and
1579 // a property within that node, although it is possible to evaluate
1580 // expressions from inside Tcl code.
1582 // To avoid passing too many arguments around the various
1583 // evaluation-related routines, a utility class is provided.
1585 class CdlEvalContext {
1587 friend class CdlTest;
1591 CdlTransaction transaction;
1593 CdlProperty property;
1594 CdlToplevel toplevel;
1596 CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
1599 // Given a reference inside an expression, try to resolve this to either
1600 // a node or, more specifically, a valuable.
1601 CdlNode resolve_reference(CdlExpression, int);
1602 CdlValuable resolve_valuable_reference(CdlExpression, int);
1604 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
1605 CYGDBG_DECLARE_MEMLEAK_COUNTER();
1610 // Illegal operation, the three fields must always be supplied,
1611 // although they may be zero.
1615 CdlEvalContext_Invalid = 0,
1616 CdlEvalContext_Magic = 0x03434be9
1617 } cdlevalcontext_cookie;
1622 //{{{ CdlSimpleValue
1624 // ----------------------------------------------------------------------------
1625 // Expression evaluation happens in terms of CdlSimpleValue objects.
1626 // In CDL all values are strings, but for the purposes of arithmetic
1627 // these strings sometimes have to be interpreted as integers or as
1628 // double precision numbers. Sometimes there is a choice, for example
1629 // the equality operator == can mean numerical or string comparison.
1630 // The basic rules that get applied are:
1632 // 1) if the current value has an integer representation then
1633 // use this by preference. This means that an expression
1634 // of the form (CYGNUM_XXX != 0x100) will do a integer
1635 // comparison if possible.
1637 // 2) otherwise if the current value can be interpreted as a
1638 // double precision number, use that representation.
1639 // All integers can be interpreted as doubles (at the risk
1640 // of some loss of precision), so the representation as
1641 // a double should only be used if the integer representation
1642 // is inappropriate.
1644 // 3) otherwise interpret the value as a string.
1646 // The default value is 0.
1648 class CdlSimpleValue {
1650 friend class CdlTest;
1655 CdlSimpleValue(std::string);
1656 CdlSimpleValue(cdl_int);
1657 CdlSimpleValue(double);
1658 CdlSimpleValue(const CdlSimpleValue&);
1659 CdlSimpleValue(bool);
1662 CdlSimpleValue& operator=(const CdlSimpleValue&);
1663 CdlSimpleValue& operator=(std::string);
1664 CdlSimpleValue& operator=(cdl_int);
1665 CdlSimpleValue& operator=(double);
1667 CdlSimpleValue& operator=(bool);
1669 bool operator==(const CdlSimpleValue&) const;
1670 bool operator!=(const CdlSimpleValue&) const;
1671 bool operator==(std::string arg) const
1673 CdlSimpleValue val(arg);
1674 return *this == val;
1676 bool operator==(cdl_int arg) const
1678 CdlSimpleValue val(arg);
1679 return *this == val;
1681 bool operator==(double arg) const
1683 CdlSimpleValue val(arg);
1684 return *this == val;
1686 bool operator!=(std::string arg) const
1688 CdlSimpleValue val(arg);
1689 return *this != val;
1691 bool operator!=(cdl_int arg) const
1693 CdlSimpleValue val(arg);
1694 return *this != val;
1696 bool operator!=(double arg) const
1698 CdlSimpleValue val(arg);
1699 return *this != val;
1702 void set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
1703 std::string get_value() const;
1705 bool has_integer_value() const;
1706 void set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
1707 cdl_int get_integer_value() const;
1709 bool has_double_value() const;
1710 void set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
1711 double get_double_value() const;
1713 CdlValueFormat get_value_format() const;
1714 void set_value_format(CdlValueFormat);
1715 void set_value_format(CdlSimpleValue&);
1716 void set_value_format(CdlSimpleValue&, CdlSimpleValue&);
1718 static void eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
1720 // For expression evaluation, it is often convenient to get hold
1721 // of a boolean as well. This may indicate a non-empty string
1722 // or a non-zero value.
1723 bool get_bool_value() const;
1725 // This class is too simple to warrant even a cookie validation.
1726 bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
1735 double_valid = 0x02,
1736 string_valid = 0x04,
1738 double_invalid = 0x10
1740 mutable int valid_flags;
1741 mutable std::string value;
1742 mutable cdl_int int_value;
1743 mutable double double_value;
1744 CdlValueFormat format;
1750 // ----------------------------------------------------------------------------
1751 // Evaluating a list expression results in a set of possible values, but
1752 // unlike the original list expression these values are now constant and
1753 // can have no dependencies on CDL entities. As with list expressions the
1754 // main operation on a list value is to detect membership, but using
1755 // list values allows multiple potential members to be tested without
1756 // repeated expression evaluation. The main use of list values is implicit
1757 // in libcdl, each list expression contains a mutable cached list value.
1759 // A list value contains five sets of data:
1761 // 1) separate vectors of strings, integers, and floating point constants.
1762 // Having separate vectors of integers and floating points avoids
1763 // problems when numbers can be represented in different formats.
1764 // 2) a vector of cdl_int pairs for ranges of integer data
1765 // 3) a vector of double pairs for ranges of floating point data
1767 // Any of these vectors may be empty, but at least one of the vectors should
1768 // contain useful data. Possibly there should also be tables for cdl_int and
1769 // double to avoid unnecessary string conversions.
1771 class CdlListValue {
1773 friend class CdlTest;
1775 // A list value will only be filled in when a list expression is evaluated.
1776 // The members cannot be updated by other means.
1777 friend class CdlListExpressionBody;
1783 CdlListValue(const CdlListValue&);
1784 CdlListValue& operator=(const CdlListValue&);
1786 bool is_member(CdlSimpleValue&) const;
1787 bool is_member(std::string, bool = true) const;
1788 bool is_member(cdl_int, bool = true) const;
1789 bool is_member(double, bool = true) const;
1791 // These provide access to the raw data, for example if it is
1792 // necessary to suggest a legal value to the user.
1793 const std::vector<CdlSimpleValue>& get_table() const;
1794 const std::vector<std::pair<cdl_int, cdl_int> >& get_integer_ranges() const;
1795 const std::vector<std::pair<double, double> >& get_double_ranges() const;
1797 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
1798 CYGDBG_DECLARE_MEMLEAK_COUNTER();
1801 std::vector<CdlSimpleValue> table;
1802 std::vector<std::pair<cdl_int, cdl_int> > integer_ranges;
1803 std::vector<std::pair<double, double> > double_ranges;
1806 CdlListValue_Invalid = 0,
1807 CdlListValue_Magic = 0x2183a943
1808 } cdllistvalue_cookie;
1814 // ----------------------------------------------------------------------------
1815 // Values in CDL are non-trivial compared with some other languages.
1816 // Even though CDL is not a fully-typed language, it does still have
1817 // four different flavors to consider. There is also the problem that
1818 // an entity may have up to four different values which should be
1819 // stored (default, inferred, wizard, user), with the ability to
1820 // switch between them. The CdlValue class provides support for this.
1822 // CdlValue objects are not normally updated explicitly. Instead
1823 // higher level code deals with CdlValuable objects, which inherit
1824 // privately from CdlValue. Modifications to CdlValuables happen in
1825 // the context of a transaction.
1827 // The first concept to take into account is the flavor. There
1828 // are four flavors, None, Bool, BoolData and Data. The member
1829 // function get_flavor() can be used to obtain the current flavor.
1831 // CdlValueFlavor CdlValue::get_flavor() const;
1833 // Values may be enabled or disabled. Values of flavor None
1834 // and Data are always enabled. Values of flavor Bool or BoolData
1835 // may or may not be enabled, by default they are disabled.
1837 // bool CdlValue::is_enabled(...) const;
1839 // (The optional argument to is_enabled() is discussed later).
1841 // Values of flavor BoolData and Data also have a string value,
1842 // which can be interpreted as an integer or a double under
1843 // the right circumstances.
1845 // std::string CdlValue::get_value(...) const;
1846 // bool CdlValue::has_integer_value(...) const;
1847 // bool CdlValue::has_double_value(...) const;
1848 // cdl_int CdlValue::get_integer_value(...) const;
1849 // double CdlValue::get_double_value(...) const;
1851 // This is equivalent to a CdlSimpleValue object, and in fact
1852 // that is the internal representation. It is possible to
1853 // get hold of the CdlSimpleValue object directly:
1855 // CdlSimpleValue CdlValue::get_simple_value(...) const;
1857 // The get_integer_value() and get_double_value() members should
1858 // only be used if you are confident that the current value has
1859 // an integer or double representation. Otherwise the result is
1862 // The optional argument to these member functions represents
1863 // the source. A value can be set from four different sources:
1864 // the default value (usually either 0 or the result of
1865 // evaluating a default_value property); an inferred value,
1866 // determined by the inference engine; a wizard value, i.e.
1867 // what a CDL wizard believes the correct value to be based
1868 // on user input; and a user value, something explicitly
1869 // set by the end user. These have different priorities:
1870 // the inference engine can override default values but not
1871 // user values. A CdlValue object keeps track of the current
1874 // CdlValueSource CdlValue::get_source() const;
1876 // If no argument is given to e.g. is_enabled() then the
1877 // current source is used. Otherwise it is possible to find
1878 // out whether or not the entity is enabled for each of the
1881 // The default source is always defined, the others may or
1882 // may not be. It is possible to find out for each source
1883 // whether or not a value has been set.
1885 // bool CdlValue::has_source(CdlValueSource) const;
1888 // Updating values normally happens in the CdlValuable class,
1889 // but the member functions are the same. There is a member
1890 // function to change the flavor:
1892 // void CdlValue::set_flavor(CdlValueFlavor);
1894 // However this member function is intended only for use by the
1895 // library itself. An entity's flavor is normally defined by CDL data,
1896 // and should not be updated explicitly by application code.
1898 // There are two member functions to manipulate the value source:
1900 // void CdlValue::set_source(CdlValueSource);
1901 // void CdlValue::invalidate_source(CdlValueSource);
1903 // The first function can be used if e.g. the user wants to
1904 // change his or her mind and go back to the default value
1905 // rather than a user value. The user value is not forgotten
1906 // and can be reinstated.
1908 // invalidate_source() can be used to completely cancel a
1909 // value source. If that source happens to be the current one
1910 // then the current source will be adjusted appropriately.
1911 // It is illegal to attempt to invalidate the default source.
1913 // For values with flavor Bool and BoolData, there are three
1914 // member functions that can be used to control the enabled
1917 // void CdlValue::set_enabled(bool, CdlValueSource);
1918 // void CdlValue::enable(CdlValueSource);
1919 // void CdlValue::disable(CdlValueSource);
1921 // Note that when updating a CdlValue object the source should
1922 // be known and must be specified. If the source has a higher
1923 // priority than the current one then it will automatically
1924 // become the new source. On the rare occasion that this is
1925 // not desired, set_source() will have to be used afterwards
1926 // to reset the current source.
1928 // For values with flavor BoolData and Data the following
1929 // member functions are available to change the value string:
1931 // void CdlValue::set_value(std::string, CdlValueSource);
1932 // void CdlValue::set_value(cdl_int, CdlValueSource);
1933 // void CdlValue::set_value(double, CdlvalueSource);
1934 // void CdlValue::set_value(CdlSimpleValue&, CdlValueSource);
1936 // For values with flavor BoolData is is possible to
1937 // combine updating the enabled flag and the string value:
1939 // void CdlValue::set_enabled_and_value(bool, std::string, CdlValueSource);
1940 // void CdlValue::set_enabled_and_value(bool, cdl_int, CdlValueSource);
1941 // void CdlValue::set_enabled_and_value(bool, double, CdlValueSource);
1942 // void CdlValue::set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
1943 // void CdlValue::enable_and_set_value(std::string, CdlValueSource);
1944 // void CdlValue::enable_and_set_value(cdl_int, CdlValueSource);
1945 // void CdlValue::enable_and_set_value(double, CdlValueSource);
1946 // void CdlValue::enable_and_set_value(CdlSimpleValue&, CdlValueSource);
1947 // void CdlValue::disable_and_set_value(std::string, CdlValueSource);
1948 // void CdlValue::disable_and_set_value(cdl_int, CdlValueSource);
1949 // void CdlValue::disable_and_set_value(double, CdlValueSource);
1950 // void CdlValue::disable_and_set_value(CdlSimpleValue&, CdlValueSource);
1952 // Obviously many of these functions are just simple inlines.
1954 // There is one final member function:
1956 // void CdlValue::set(CdlSimpleValue, CdlValueSource);
1958 // This member function is defined to do the right thing,
1959 // whatever the flavor happens to be.
1963 friend class CdlTest;
1967 CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
1968 virtual ~CdlValue();
1969 CdlValue(const CdlValue&);
1970 CdlValue& operator=(const CdlValue&);
1972 CdlValueFlavor get_flavor() const;
1973 CdlValueSource get_source() const;
1974 bool has_source(CdlValueSource) const;
1976 bool is_enabled(CdlValueSource = CdlValueSource_Current) const;
1977 std::string get_value(CdlValueSource = CdlValueSource_Current) const;
1978 bool has_integer_value(CdlValueSource = CdlValueSource_Current) const;
1979 bool has_double_value(CdlValueSource = CdlValueSource_Current) const;
1980 cdl_int get_integer_value(CdlValueSource = CdlValueSource_Current) const;
1981 double get_double_value(CdlValueSource = CdlValueSource_Current) const;
1982 CdlSimpleValue get_simple_value(CdlValueSource = CdlValueSource_Current) const;
1984 void set_source(CdlValueSource);
1985 void invalidate_source(CdlValueSource);
1987 void set_enabled(bool, CdlValueSource);
1988 void enable(CdlValueSource source)
1990 set_enabled(true, source);
1992 void disable(CdlValueSource source)
1994 set_enabled(false, source);
1997 void set_value(CdlSimpleValue&, CdlValueSource);
1998 void set_value(std::string data, CdlValueSource source)
2000 CdlSimpleValue val(data);
2001 set_value(val, source);
2003 void set_integer_value(cdl_int data, CdlValueSource source)
2005 CdlSimpleValue val(data);
2006 set_value(val, source);
2008 void set_double_value(double data, CdlValueSource source)
2010 CdlSimpleValue val(data);
2011 set_value(val, source);
2013 void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
2014 void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
2016 CdlSimpleValue val(data);
2017 set_enabled_and_value(enabled, val, source);
2019 void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
2021 CdlSimpleValue val(data);
2022 set_enabled_and_value(enabled, val, source);
2024 void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
2026 CdlSimpleValue val(data);
2027 set_enabled_and_value(enabled, val, source);
2029 void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2031 set_enabled_and_value(true, val, source);
2033 void enable_and_set_value(std::string data, CdlValueSource source)
2035 set_enabled_and_value(true, data, source);
2037 void enable_and_set_value(cdl_int data, CdlValueSource source)
2039 set_enabled_and_value(true, data, source);
2041 void enable_and_set_value(double data, CdlValueSource source)
2043 set_enabled_and_value(true, data, source);
2045 void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2047 set_enabled_and_value(false, val, source);
2049 void disable_and_set_value(std::string data, CdlValueSource source)
2051 set_enabled_and_value(false, data, source);
2053 void disable_and_set_value(cdl_int data, CdlValueSource source)
2055 set_enabled_and_value(false, data, source);
2057 void disable_and_set_value(double data, CdlValueSource source)
2059 set_enabled_and_value(false, data, source);
2062 void set(CdlSimpleValue&, CdlValueSource);
2064 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2065 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2067 // This should only be used by the library itself.
2068 void set_flavor(CdlValueFlavor);
2074 CdlValueFlavor flavor;
2075 CdlValueSource current_source;
2077 // FIXME: a static const member should be used for the array
2078 // sizes, but VC++ does not support that part of the language.
2079 // FIXME: std::bitset should be used here. Using lots of separate
2080 // bools here is inefficient.
2081 bool source_valid[4];
2083 CdlSimpleValue values[4];
2086 CdlValue_Invalid = 0,
2087 CdlValue_Magic = 0x41837960
2092 //{{{ CdlSubexpression
2094 // ----------------------------------------------------------------------------
2095 // Expressions come into existence primarily as the result of reading
2096 // in certain properties like default_value in CDL data. It is also
2097 // possible for expressions to be generated and evaluated on the fly
2098 // inside Tcl code, but that is expected to be a comparatively rare
2099 // events. Expression objects always live on the heap, usually only
2100 // in derived classes.
2102 // An ordinary expression evaluates to a single value. There are two
2103 // other types of expression in the CDL language, goal expressions and
2104 // list expression. A goal expression is essentially a set of ordinary
2105 // expressions with implicit &&'s between them. A list expression
2106 // is a set of expressions that can be evaluated to a constant vector,
2107 // plus pairs of expressions that constitute ranges. Again goal and
2108 // list expressions only live on the heap.
2110 // Both parsing an evaluation involve tokens for the various
2111 // operators. The inference engine, conflict reporting code, and
2112 // other diagnostic code will also need to have ready access to
2113 // this information. Hence it makes a bit more sense to have
2114 // the enum outside the expression class.
2117 CdlExprOp_Invalid = 0,
2118 CdlExprOp_EOD = 1, // End of data reached
2119 CdlEXprOp_Command = 2, // [tcl code]
2120 CdlExprOp_Variable = 3, // $tcl_variable
2121 CdlExprOp_StringConstant = 4, // "hello"
2122 CdlExprOp_IntegerConstant = 5, // 123
2123 CdlExprOp_DoubleConstant = 6, // 3.1415
2124 CdlExprOp_Reference = 7, // CYGPKG_INFRA
2125 CdlExprOp_Range = 8, // x to y
2126 CdlExprOp_Negate = 9, // -x
2127 CdlExprOp_Plus = 10, // +x
2128 CdlExprOp_LogicalNot = 11, // !x
2129 CdlExprOp_BitNot = 12, // ~x
2130 CdlExprOp_Indirect = 13, // *x
2131 CdlExprOp_Active = 14, // ?x
2132 CdlExprOp_Function = 15, // sin(x)
2133 CdlExprOp_Multiply = 16, // x * y
2134 CdlExprOp_Divide = 17, // x / y
2135 CdlExprOp_Remainder = 18, // x % y
2136 CdlExprOp_Add = 19, // x + y
2137 CdlExprOp_Subtract = 20, // x - y
2138 CdlExprOp_LeftShift = 21, // x << y
2139 CdlExprOp_RightShift = 22, // x >> y
2140 CdlExprOp_LessThan = 23, // x < y
2141 CdlExprOp_LessEqual = 24, // x <= y
2142 CdlExprOp_GreaterThan = 25, // x > y
2143 CdlExprOp_GreaterEqual = 26, // x >= y
2144 CdlExprOp_Equal = 27, // x == y
2145 CdlExprOp_NotEqual = 28, // x != y
2146 CdlExprOp_BitAnd = 29, // x & y
2147 CdlExprOp_BitXor = 30, // x ^ y
2148 CdlExprOp_BitOr = 31, // x | y
2149 CdlExprOp_And = 32, // x && y
2150 CdlExprOp_Or = 33, // x || y
2151 CdlExprOp_Cond = 34, // x ? a : b
2152 CdlExprOp_StringConcat = 35, // x . y
2153 CdlExprOp_Implies = 36, // x implies y
2154 CdlExprOp_Xor = 37, // x xor y
2155 CdlExprOp_Eqv = 38 // x eqv y
2158 // ----------------------------------------------------------------------------
2159 // A subexpression consists of an operation, possibly some constant
2160 // data, and possibly indices into the subexpression vector.
2161 // Normally some unions would be used, but unions and objects such
2162 // as std::string do not mix, and the amount of memory involved is
2163 // not big enough to really worry about.
2165 #define CdlFunction_MaxArgs 3
2166 struct CdlSubexpression {
2169 CdlSimpleValue constants; // String, integer or double constant
2170 int reference_index; // iff CdlExprOp_Reference
2172 int lhs_index; // for all non-constant operators
2173 int rhs_index; // for binary and ternary operators only
2174 int rrhs_index; // only for ternary operators.
2176 int func; // iff CdlExprOp_Function
2177 int args[CdlFunction_MaxArgs];
2183 // ----------------------------------------------------------------------------
2184 // Generic support for function parsing, evaluation, and inference. The
2185 // implementation is extensible so that functions can be added to the
2186 // core via static constructors.
2190 friend class CdlTest;
2193 CdlFunction(const char* /* name */, int /* no_args */,
2194 void (*)(CdlExpression, const CdlSubexpression&),
2195 void (*)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
2196 bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int),
2197 bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)
2201 static bool is_function(std::string, int&);
2202 static std::string get_name(int);
2203 static int get_args_count(int);
2205 static void check(CdlExpression, const CdlSubexpression&);
2206 static void eval(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
2207 static bool infer_bool(CdlTransaction, CdlExpression, unsigned int, bool, int);
2208 static bool infer_value(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2210 static void (*null_check)(CdlExpression, const CdlSubexpression&);
2211 static bool (*null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int);
2212 static bool (*null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2217 // Keep track of all functions in the system
2218 static std::vector<CdlFunction*> all_functions;
2220 // Each function object is given a unique id during initialization
2224 // Provided by the constructor
2227 void (*check_fn)(CdlExpression, const CdlSubexpression&);
2228 void (*eval_fn)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
2229 bool (*infer_bool_fn)(CdlTransaction, CdlExpression, unsigned int, bool, int);
2230 bool (*infer_value_fn)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2232 // The default constructor is illegal
2239 // ----------------------------------------------------------------------------
2240 // And now for the expression class itself.
2242 class CdlExpressionBody {
2244 friend class CdlTest;
2248 // The default constructor is basically a no-op, new expression
2249 // objects only get created as a consequence of parsing. However
2250 // it exists and is protected for the convenience of derived
2251 // classes. The copy constructor is protected, allowing parsing
2252 // code to first parse an expression and then copy the expression
2253 // into a higher level object. The assignment operator is illegal.
2254 // There is no reason to hide the destructor.
2255 virtual ~CdlExpressionBody();
2257 // An expression involves three pieces of data. There is a vector
2258 // of subexpressions. It is also necessary to know where
2259 // evaluation should being, in accordance with operator precedence
2260 // rules. And there is a vector of CdlReference objects - this
2261 // needs to be kept separate from the subexpression vector because
2262 // CdlReference objects are comparatively tricky.
2264 // All of this data is public and can be readily inspected by the
2265 // inference engine, by conflict detection code, by diagnostic
2267 std::vector<CdlSubexpression> sub_expressions;
2268 int first_subexpression;
2269 std::vector<CdlReference> references;
2270 bool update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2272 // There are a number of parsing functions. The first one is
2273 // used by higher-level code to parse a single expression. Its
2274 // argument is a single string (which may be the result of
2275 // concatenating several Tcl arguments), and at the end of the
2276 // parse operation there should be no further data. The result
2277 // will either be a new expression object or a parsing exception
2278 // to be caught by higher level code.
2279 static CdlExpression parse(std::string);
2281 // This is used when parsing list expressions, which involve a
2282 // sequence of ordinary expressions and possibly range operators.
2283 // The whole list expression lives in a single string, and it is
2284 // necessary to provide an index indicating where in the string
2285 // parsing should begin. It is also useful to return details of
2286 // the token that caused parsing to terminate (EOD, Range, or
2287 // the start of something else).
2288 static CdlExpression parse(std::string, int&, CdlExprOp&, int&);
2290 // A goal expression is derived from an ordinary expression but
2291 // has somewhat different rules for evaluating. Parsing a goal
2292 // expression involves parsing a number of ordinary expressions
2293 // with implicit && operators between them, and it requires
2294 // a parsing function that can be used to extend an existing
2297 // NOTE: possibly this should should be a protected member, since
2298 // its main use is in parsing goal expressions.
2299 static void continue_parse(CdlExpression, std::string, int&, CdlExprOp&, int&);
2301 // Evaluating expressions. Note that this may fail at run-time
2302 // because of errors that cannot be caught sensibly when the
2303 // expression is read in, for example arithmetic overflow or
2304 // division by zero. Because such failures are a possibility
2305 // anyway no special action is taken to prevent an expression
2306 // with e.g. an unresolved reference from being evaluated.
2308 // eval() is the public interface, and manages
2309 // CdlConflict_EvalException objects. eval_internal() is for use
2310 // by list and goal expressions.
2311 void eval(CdlEvalContext&, CdlSimpleValue&);
2312 void eval_internal(CdlEvalContext&, CdlSimpleValue&);
2313 void eval_subexpression(CdlEvalContext&, int, CdlSimpleValue&);
2315 // The full original expression is useful for diagnostics purposes
2316 std::string get_original_string() const;
2318 bool check_this(cyg_assert_class_zeal cyg_quick) const;
2319 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2323 // The default constructor does very little, the main work
2324 // is done by the various parsing functions. However it is
2325 // available to derived classes, especially goal expressions.
2326 CdlExpressionBody();
2328 // The copy constructor has to be usable by derived classes,
2329 // e.g. CdlExpressionProperty
2330 CdlExpressionBody(const CdlExpressionBody&);
2335 // The assignment operator is illegal.
2336 CdlExpressionBody& operator=(const CdlExpressionBody&);
2338 // The string that was parsed originally
2339 std::string expression_string;
2342 CdlExpressionBody_Invalid = 0,
2343 CdlExpressionBody_Magic = 0x760293a3
2344 } cdlexpressionbody_cookie;
2348 //{{{ CdlListExpression
2350 // ----------------------------------------------------------------------------
2351 // The main use of list expressions is for the legal_values
2352 // properties. Essentially a list expression is just a vector of
2353 // ordinary expressions and ranges of expressions.
2355 class CdlListExpressionBody {
2357 friend class CdlTest;
2361 // Availability of constructors etc. is as per the ordinary
2362 // expression class.
2363 virtual ~CdlListExpressionBody();
2365 // The data associated with a list expression is a vector of
2366 // expressions, plus a vector of expression pairs constituting
2367 // ranges. As with ordinary expressions the data is fully public
2368 // and can be readily examined by e.g. the inference engine.
2369 std::vector<CdlExpression> data;
2370 std::vector<std::pair<CdlExpression,CdlExpression> > ranges;
2372 // Parsing. This involves taking a single string, typically from
2373 // a CDL script, and parsing one or more ordinary expressions.
2374 static CdlListExpression parse(std::string);
2376 // Evaluation support. A list expression evaluates to a list value.
2377 void eval(CdlEvalContext&, CdlListValue&);
2379 // More commonly client code is going to be interested in whether
2380 // or not a particular value is a legal member. The result
2381 // cache ensures that it is possible to
2382 bool is_member(CdlEvalContext&, CdlSimpleValue&);
2383 bool is_member(CdlEvalContext&, std::string);
2384 bool is_member(CdlEvalContext&, cdl_int);
2385 bool is_member(CdlEvalContext&, double);
2387 // The full original expression is useful for diagnostics purposes
2388 std::string get_original_string() const;
2390 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2391 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2394 CdlListExpressionBody(const CdlListExpressionBody&);
2395 bool update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2399 CdlListExpressionBody();
2400 CdlListExpressionBody& operator=(const CdlListExpressionBody&);
2402 void eval_internal(CdlEvalContext&, CdlListValue&);
2403 std::string expression_string;
2406 CdlListExpressionBody_Invalid = 0,
2407 CdlListExpressionBody_Magic = 0x7da4bcc2
2408 } cdllistexpressionbody_cookie;
2412 //{{{ CdlGoalExpression
2414 // ----------------------------------------------------------------------------
2415 // A goal expression inherits privately from ordinary expressions. Essentially
2416 // a goal expression is simply a set of ordinary expressions separated by &&,
2417 // but it can only be evaluated to a boolean. The parse() and eval() members
2418 // of the base class should not be exposed. There is a member to get hold of
2419 // the underlying ordinary expression, for use by e.g. the inference engine.
2421 class CdlGoalExpressionBody : private CdlExpressionBody {
2423 friend class CdlTest;
2425 typedef CdlExpressionBody inherited;
2428 virtual ~CdlGoalExpressionBody();
2430 static CdlGoalExpression parse(std::string);
2432 // A few variants of the eval() member, with a choice of returning
2433 // by value or by reference. The latter provide consistency with the
2434 // other expression classes.
2435 bool eval(CdlEvalContext&);
2436 void eval(CdlEvalContext&, bool&);
2438 // Provide public access to the underlying expression object,
2439 // useful for the inference engine
2440 CdlExpression get_expression();
2442 // The full original expression is useful for diagnostics purposes
2443 std::string get_original_string() const;
2445 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2446 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2449 CdlGoalExpressionBody(const CdlGoalExpressionBody&);
2454 CdlGoalExpressionBody();
2455 CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
2456 void eval_internal(CdlEvalContext&, bool&);
2458 std::string expression_string;
2461 CdlGoalExpressionBody_Invalid = 0,
2462 CdlGoalExpressionBody_Magic = 0x5a58bb24
2463 } cdlgoalexpressionbody_cookie;
2469 // ----------------------------------------------------------------------------
2470 // A utility class related to inference. This exports the main functions
2471 // needed, allowing e.g. per-function inference routines from func.cxx to
2472 // interact with the main inference engine.
2476 static bool make_active(CdlTransaction, CdlNode, int /* level */);
2477 static bool make_inactive(CdlTransaction, CdlNode, int /* level */);
2478 static bool set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, int /* level */);
2479 static bool set_valuable_bool(CdlTransaction, CdlValuable, bool, int /* level */);
2480 static bool subexpr_value(CdlTransaction, CdlExpression, unsigned int /* index */, CdlSimpleValue& goal, int /* level */);
2481 static bool subexpr_bool(CdlTransaction, CdlExpression, unsigned int /* index */, bool, int /* level */);
2490 //{{{ CdlConflict classes
2492 // ----------------------------------------------------------------------------
2493 // As a configuration is created and modified there will be times when
2494 // things are not completely consistent. There may be a reference to
2495 // some option that is not in any package in the current
2496 // configuration. An option may have an invalid value, possibly as a
2497 // side effect of a change to some other option. There may be a
2498 // dependency that is not satisfied. There may be other types of
2501 // The library provides a base class CdlConflict, and a number of
2502 // derived classes for common types of conflict such as unresolved
2503 // references. All conflicts are associated with a CdlNode and a
2504 // property within that. It is possible to use dynamic_cast<> to find
2505 // out the exact type of a conflict, or alternatively to use the
2506 // virtual member function get_explanation().
2508 // Conflicts may be disabled by the user if they are not actually
2509 // important as far as application code is concerned. In other words
2510 // the end user is allowed to override the constraints specified in
2511 // the CDL. This information is saved with the configuration data.
2512 // Preferably the user should give an explanation for why the conflict
2513 // is disabled, to serve as a reminder some months later when the
2514 // configuration is reloaded.
2517 // Conflicts have a fairly complicated life cycle. First it is
2518 // necessary to distinguish between structural and normal conflicts. A
2519 // structural conflict is typically caused by a reference to a
2520 // non-existent valuable. These conflicts are generally created only
2521 // when something is loaded, and only go away when something is
2522 // unloaded. A normal conflict is typically related to a value, for
2523 // example a value outside the legal range, or a "requires" property
2524 // that is not satisfied.
2526 // Conflicts are created and destroyed in the context of a
2527 // transaction, which in turn operates in the context of a toplevel.
2528 // If the transaction is committed then new conflicts get added to the
2529 // appropriate toplevel list, and destroyed conflicts get removed from
2530 // the toplevel list. The transaction field indicates whether the
2531 // conflict is currently per-transaction or global.
2533 // Transactions may get nested, i.e. a conflict may get created as
2534 // part of a sub-transaction, and when that sub-transaction is committed
2535 // the conflict is moved to the parent transaction.
2537 // For each toplevel, libcdl keeps track of all conflicts. This only
2538 // applies to committed conflicts, per-transaction conflicts are not
2539 // accessible in this way.
2541 // As part of a transaction, libcdl may attempt to find solutions for
2542 // particular conflicts, and those solutions may get installed
2543 // automatically. No attempt is made to keep track of solutions
2544 // on a global basis, only on a per-transaction basis.
2546 class CdlConflictBody {
2548 friend class CdlTest;
2550 // Transactions and conflicts are closely connected
2551 friend class CdlTransactionBody;
2555 // Creation happens only inside a derived class.
2556 // Clearing a conflict only happens inside transactions.
2557 // Destroying a conflict only happens from inside a
2558 // per-transaction clear(), or during a transaction commit.
2560 // Is this conflict part of a transaction, or has it been committed to the toplevel.
2561 CdlTransaction get_transaction() const;
2563 // Is inference implemented for this type of conflict?
2564 virtual bool resolution_implemented() const;
2566 // Try to resolve an existing global conflict. A new transaction
2567 // is created for this operation, the conflict is resolved within
2568 // that transaction, and then CdlTransaction::body() is used to
2569 // handle inference callbacks, commits, etc. See also
2570 // CdlToplevel::resolve_conflicts() and
2571 // CdlToplevel::resolve_all_conflicts(). The conflict may cease to
2572 // exist as a side-effect of this call.
2575 // Keep track of whether or not this conflict has a solution
2576 // 1) a conflict may have a current solution. This gets invalidated
2577 // whenever there is a change to a value that was referenced
2578 // while identifying the solution.
2580 // A current solution is indicated by a non-empty solution vector.
2582 // 2) a conflict may not have a current solution. Again this gets
2583 // invalidated whenever a referred value changes. There is a boolean
2584 // to keep track of this.
2586 // 3) a conflict may not have a current solution, but another run of
2587 // the inference engine may find one.
2588 bool has_known_solution() const;
2589 bool has_no_solution() const;
2590 const std::vector<std::pair<CdlValuable, CdlValue> >& get_solution() const;
2591 const std::set<CdlValuable>& get_solution_references() const;
2592 void clear_solution();
2594 // Provide a text message "explaining" the conflict.
2595 // This only makes sense for derived classes.
2596 virtual std::string get_explanation() const = 0;
2598 // Basic information access.
2599 CdlNode get_node() const;
2600 CdlProperty get_property() const;
2601 bool is_structural() const;
2603 // Enabling and disabling conflicts currently happens outside the
2604 // context of any transaction.
2605 // FIXME: these are not currently implemented. It would be necessary
2606 // to store the information in the savefile, which requires an
2607 // unambiguous way of identifying a conflict that is likely to
2608 // survice package version changes.
2609 void disable(std::string);
2611 bool is_enabled() const;
2612 std::string get_disabled_reason() const;
2614 bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
2615 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2618 CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
2620 // The destructor gets accessed from inside the friend transaction class,
2621 // either during a clear_conflict() or during a transaction commit.
2622 virtual ~CdlConflictBody();
2624 // All conflicts are associated with a node and a property.
2625 // This information will be useful to derived classes'
2626 // implementations of get_explanation()
2628 CdlProperty property;
2632 // Attempt to resolve a conflict in a sub-transaction
2633 // This is invoked from inside the transaction resolve code.
2634 // There are additional exported interfaces inside and outside
2635 // the transaction class.
2636 virtual bool inner_resolve(CdlTransaction, int);
2638 // Keep track of the transaction in which this conflict was created.
2639 // The field is cleared at the end of a transaction.
2640 CdlTransaction transaction;
2642 // Usually the derived class will decide whether or not
2643 // this conflict is structural in nature, but the data
2644 // needs to be available at base constructor time so
2645 // a virtual function is not appropriate.
2650 std::vector<std::pair<CdlValuable, CdlValue> > solution;
2651 std::set<CdlValuable> solution_references;
2652 void update_solution_validity(CdlValuable);
2654 // Users may disable a conflict. Usually they will have to
2655 // supply a reason for this.
2660 CdlConflictBody_Invalid = 0,
2661 CdlConflictBody_Magic = 0x073e8853
2662 } cdlconflictbody_cookie;
2664 // Illegal operations. Conflicts always live on the heap.
2666 CdlConflictBody(const CdlConflictBody&);
2667 CdlConflictBody& operator=(const CdlConflictBody&);
2670 // ----------------------------------------------------------------------------
2671 // An unresolved conflict means that there is a reference in some
2672 // property to an entity that is not yet in the current configuration.
2673 // The class provides convenient access to the name of the unresolved
2676 class CdlConflict_UnresolvedBody : public CdlConflictBody {
2678 friend class CdlTest;
2681 static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
2683 std::string get_target_name() const;
2684 std::string get_explanation() const;
2685 static bool test(CdlConflict);
2686 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2687 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2692 virtual ~CdlConflict_UnresolvedBody();
2693 CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2694 std::string target_name;
2696 CdlConflict_UnresolvedBody_Invalid = 0,
2697 CdlConflict_UnresolvedBody_Magic = 0x1b24bb8a
2698 } cdlconflict_unresolvedbody_cookie;
2700 CdlConflict_UnresolvedBody();
2701 CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
2702 CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
2705 // ----------------------------------------------------------------------------
2706 // An illegal value can be caused because of a number of properties:
2707 // legal_values, check_proc, entry_proc, ... In the case of the latter
2708 // the Tcl code should provide text explaining why the value is
2711 class CdlConflict_IllegalValueBody : public CdlConflictBody {
2713 friend class CdlTest;
2717 static void make(CdlTransaction, CdlNode, CdlProperty);
2719 bool resolution_implemented() const;
2721 std::string get_explanation() const;
2722 void set_explanation(std::string);
2723 static bool test(CdlConflict);
2724 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2725 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2730 virtual ~CdlConflict_IllegalValueBody();
2731 bool inner_resolve(CdlTransaction, int);
2732 CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
2733 std::string explanation;
2735 CdlConflict_IllegalValueBody_Invalid = 0,
2736 CdlConflict_IllegalValueBody_Magic = 0x4fb27ed1
2737 } cdlconflict_illegalvaluebody_cookie;
2739 CdlConflict_IllegalValueBody();
2740 CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
2741 CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
2744 // ----------------------------------------------------------------------------
2745 // There are times when expression evaluation will fail, e.g. because of
2746 // a division by zero. The explanation is supplied by the evaluation code.
2748 class CdlConflict_EvalExceptionBody : public CdlConflictBody {
2750 friend class CdlTest;
2754 static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
2756 std::string get_explanation() const;
2757 void set_explanation(std::string); // mainly for internal use
2758 static bool test(CdlConflict);
2759 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2760 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2765 virtual ~CdlConflict_EvalExceptionBody();
2766 CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2767 std::string explanation;
2769 CdlConflict_EvalExceptionBody_Invalid = 0,
2770 CdlConflict_EvalExceptionBody_Magic = 0x7e64bc41
2771 } cdlconflict_evalexceptionbody_cookie;
2774 // ----------------------------------------------------------------------------
2775 // A goal expression evaluates to false. Producing sensible diagnostics
2776 // depends on a detailed understanding of goal expressions, which will
2777 // have to wait until the inference engine comes along.
2779 class CdlConflict_RequiresBody : public CdlConflictBody {
2781 friend class CdlTest;
2785 static void make(CdlTransaction, CdlNode, CdlProperty);
2786 bool resolution_implemented() const;
2788 std::string get_explanation() const;
2789 static bool test(CdlConflict);
2790 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2791 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2796 virtual ~CdlConflict_RequiresBody();
2797 bool inner_resolve(CdlTransaction, int);
2798 CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
2800 CdlConflict_RequiresBody_Invalid = 0,
2801 CdlConflict_RequiresBody_Magic = 0x78436331
2802 } cdlconflict_requiresbody_cookie;
2805 // ----------------------------------------------------------------------------
2806 // There is an unusual problem in the configuration data somewhere.
2807 // For example, a parent property can be resolved but the target is
2808 // not a container. There is not a lot that the user can do about
2809 // problems like this, apart from complaining to the component vendor,
2810 // but the problem should not be ignored either.
2812 class CdlConflict_DataBody : public CdlConflictBody {
2814 friend class CdlTest;
2818 static void make(CdlTransaction, CdlNode, CdlProperty, std::string);
2820 std::string get_explanation() const;
2821 static bool test(CdlConflict);
2822 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2823 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2828 virtual ~CdlConflict_DataBody();
2829 CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2830 std::string message;
2832 CdlConflict_DataBody_Invalid = 0,
2833 CdlConflict_DataBody_Magic = 0x2cec7ad8
2834 } cdlconflict_databody_cookie;
2838 //{{{ CdlProperty class and derived classes
2842 // ---------------------------------------------------------------------------
2843 // There are many different kinds of property. An alias property contains
2844 // a simple string. A check_proc property contains a fragment of Tcl code
2845 // which can be represented internally as a string, as bytecodes, or both.
2846 // A requires property contains a goal expression. ...
2848 // The implementation involves a base class CdlProperty and various
2849 // derived classes such as CdlProperty_StringBody and
2850 // CdlProperty_ExpressionBody.
2852 // New CdlProperty objects get created only when reading in CDL scripts,
2853 // while executing commands like alias and requires. These commands are
2854 // implemented as C++ functions hooked into the TCL interpreter. The
2855 // property arguments are available as an argc/argv pair. Each command
2856 // will parse and validate the arguments and then invoke an appropriate
2860 //{{{ CdlPropertyId_xxx
2862 // ----------------------------------------------------------------------------
2863 // Properties are identified by strings rather than by an enum or anything
2864 // like that. A string-based approach allows new properties to be added at
2865 // any time without invalidating an existing enum, complicating switch()
2866 // statements, etc. There are some performance issues but these are
2869 // A disadvantage of using strings is that there is a problem with
2870 // typos. Mistyping something like CdlPropertyId_Compile will generally
2871 // result in a compile-time failure. Mistyping "Complie" will cause
2872 // strange behaviour at run-time and is hard to track down.
2874 // A compromise solution is to have #define'd string constants.
2876 #define CdlPropertyId_ActiveIf "ActiveIf"
2877 #define CdlPropertyId_BuildProc "BuildProc"
2878 #define CdlPropertyId_Calculated "Calculated"
2879 #define CdlPropertyId_CancelProc "CancelProc"
2880 #define CdlPropertyId_CheckProc "CheckProc"
2881 #define CdlPropertyId_Compile "Compile"
2882 #define CdlPropertyId_ConfirmProc "ConfirmProc"
2883 #define CdlPropertyId_DecorationProc "DecorationProc"
2884 #define CdlPropertyId_DefaultValue "DefaultValue"
2885 #define CdlPropertyId_Define "Define"
2886 #define CdlPropertyId_DefineHeader "DefineHeader"
2887 #define CdlPropertyId_DefineProc "DefineProc"
2888 #define CdlPropertyId_Description "Description"
2889 #define CdlPropertyId_Dialog "Dialog"
2890 #define CdlPropertyId_Display "Display"
2891 #define CdlPropertyId_DisplayProc "DisplayProc"
2892 #define CdlPropertyId_Doc "Doc"
2893 #define CdlPropertyId_EntryProc "EntryProc"
2894 #define CdlPropertyId_Flavor "Flavor"
2895 #define CdlPropertyId_DefineFormat "DefineFormat"
2896 #define CdlPropertyId_Group "Group"
2897 #define CdlPropertyId_Hardware "Hardware"
2898 #define CdlPropertyId_IfDefine "IfDefine"
2899 #define CdlPropertyId_Implements "Implements"
2900 #define CdlPropertyId_IncludeDir "IncludeDir"
2901 #define CdlPropertyId_IncludeFiles "IncludeFiles"
2902 #define CdlPropertyId_InitProc "InitProc"
2903 #define CdlPropertyId_InstallProc "InstallProc"
2904 #define CdlPropertyId_LegalValues "LegalValues"
2905 #define CdlPropertyId_Library "Library"
2906 #define CdlPropertyId_LicenseProc "LicenseProc"
2907 #define CdlPropertyId_Make "Make"
2908 #define CdlPropertyId_Makefile "Makefile"
2909 #define CdlPropertyId_MakeObject "MakeObject"
2910 #define CdlPropertyId_NoDefine "NoDefine"
2911 #define CdlPropertyId_Object "Object"
2912 #define CdlPropertyId_Parent "Parent"
2913 #define CdlPropertyId_Requires "Requires"
2914 #define CdlPropertyId_Screen "Screen"
2915 #define CdlPropertyId_Script "Script"
2916 #define CdlPropertyId_UpdateProc "UpdateProc"
2917 #define CdlPropertyId_Wizard "Wizard"
2922 // ----------------------------------------------------------------------------
2923 // The base class is never used directly. Instead the appropriate derived
2924 // objects are instantiated and when appropriate it will be necessary to
2925 // do a dynamic cast from a CdlProperty to e.g. a CdlProperty_String.
2927 class CdlPropertyBody {
2929 friend class CdlTest;
2932 // The destructor is public, to avoid possible problems with STL.
2933 virtual ~CdlPropertyBody();
2935 // These routines provide access to the basic data.
2936 std::string get_property_name() const;
2938 // Get hold of the arguments that were present in the original data.
2939 int get_argc() const;
2940 bool has_option(std::string) const;
2941 std::string get_option(std::string) const;
2942 const std::vector<std::string>& get_argv() const;
2943 const std::vector<std::pair<std::string,std::string> >& get_options() const;
2945 // Resolve any references, or generate/update appropriate conflict
2946 // objects. The default implementation is a no-op because not all
2947 // properties involve references.
2948 virtual void update(CdlTransaction, CdlNode /* source */, CdlNode /* dest */, CdlUpdate);
2950 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2951 CYGDBG_DECLARE_MEMLEAK_COUNTER();
2955 // The legal constructor can only get invoked from a derived class
2956 // constructor. The first argument identifies the property, e.g.
2957 // CdlPropertyId_Doc (which is just #define'd to the string
2960 // The argc and argv fields provide access to the original
2961 // data in the command that resulted in the property being
2962 // constructed. Often but not always argv[0] will be the same as
2963 // the property id. The argv information is stored mainly for
2964 // diagnostics purposes, it may be removed in future to avoid
2967 // The options field is the result of parsing options such
2968 // as -library=libextras.a. It consists of a vector of
2969 // <name/value> pairs, and is usually obtained via
2970 // CdlParse::parse_options().
2971 CdlPropertyBody(CdlNode, std::string, int argc, const char* argv[], std::vector<std::pair<std::string,std::string> >&);
2974 // This string indicates the command used to define this property,
2975 // e.g. "doc" or "define_proc". It is provided to the constructor.
2978 // All property data comes out of a file and gets rid via a
2979 // Tcl interpreter. The raw file data is stored with the property,
2980 // mainly for diagnostics purposes.
2981 std::vector<std::string> argv;
2983 std::vector<std::pair<std::string, std::string> > options;
2985 // The usual set of illegal operations.
2987 CdlPropertyBody(const CdlPropertyBody&);
2988 CdlPropertyBody& operator=(const CdlPropertyBody&);
2991 CdlPropertyBody_Invalid = 0,
2992 CdlPropertyBody_Magic = 0x60dd58f4
2993 } cdlpropertybody_cookie;
2997 //{{{ CdlProperty_Minimal
2999 // ----------------------------------------------------------------------------
3000 // This class is used for properties that are simple flags, e.g. no_define.
3001 // There should be no additional data associated with such properties.
3003 class CdlProperty_MinimalBody : public CdlPropertyBody {
3005 friend class CdlTest;
3008 static CdlProperty_Minimal make(CdlNode, std::string, int, const char*[], std::vector<std::pair<std::string,std::string> >&);
3009 virtual ~CdlProperty_MinimalBody( );
3010 bool check_this( cyg_assert_class_zeal = cyg_quick ) const;
3011 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3016 typedef CdlPropertyBody inherited;
3018 CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector<std::pair<std::string,std::string> >&);
3020 CdlProperty_MinimalBody_Invalid = 0,
3021 CdlProperty_MinimalBody_Magic = 0x25625b8c
3022 } cdlproperty_minimalbody_cookie;
3024 CdlProperty_MinimalBody();
3025 CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
3026 CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
3030 //{{{ CdlProperty_String
3032 // ----------------------------------------------------------------------------
3033 // A string property contains a single piece of additional data in the form
3036 class CdlProperty_StringBody : public CdlPropertyBody {
3038 friend class CdlTest;
3041 static CdlProperty_String make(CdlNode, std::string, std::string, int, const char*[],
3042 std::vector<std::pair<std::string,std::string> >&);
3043 virtual ~CdlProperty_StringBody();
3045 std::string get_string(void) const;
3046 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3047 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3052 typedef CdlPropertyBody inherited;
3054 CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
3055 std::vector<std::pair<std::string,std::string> >&);
3058 CdlProperty_StringBody_Invalid = 0,
3059 CdlProperty_StringBody_Magic = 0x78d1ca94
3060 } cdlproperty_stringbody_cookie;
3062 // The only legal constructor supplies all the data.
3063 CdlProperty_StringBody();
3064 CdlProperty_StringBody(const CdlProperty_StringBody&);
3065 CdlProperty_StringBody& operator=(const CdlProperty_StringBody&);
3069 //{{{ CdlProperty_TclCode
3071 // ----------------------------------------------------------------------------
3072 // A TclCode property is currently equivalent to a string property. In
3073 // future this may change to allow the byte-compiled versions of the
3074 // script to be stored.
3076 // One of the properties, "screen" inside a cdl_wizard, also takes
3077 // an integer. Rather than create yet another class, this is handled
3078 // by a separate constructor.
3081 class CdlProperty_TclCodeBody : public CdlPropertyBody {
3083 friend class CdlTest;
3086 static CdlProperty_TclCode make(CdlNode, std::string, cdl_tcl_code, int, const char*[],
3087 std::vector<std::pair<std::string,std::string> >&);
3088 static CdlProperty_TclCode make(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
3089 std::vector<std::pair<std::string,std::string> >&);
3090 virtual ~CdlProperty_TclCodeBody();
3092 cdl_int get_number(void) const;
3093 const cdl_tcl_code& get_code(void) const;
3094 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3095 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3098 typedef CdlPropertyBody inherited;
3100 CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
3101 std::vector<std::pair<std::string,std::string> >&);
3106 CdlProperty_TclCodeBody_Invalid = 0,
3107 CdlProperty_TclCodeBody_Magic = 0x7b14d4e5
3108 } cdlproperty_tclcodebody_cookie;
3110 CdlProperty_TclCodeBody();
3111 CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
3112 CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
3117 //{{{ CdlProperty_StringVector
3119 // ----------------------------------------------------------------------------
3120 // This is used for multiple constant strings, as opposed to a list
3121 // expression which requires evaluation. One example is a list
3124 class CdlProperty_StringVectorBody : public CdlPropertyBody {
3126 friend class CdlTest;
3129 static CdlProperty_StringVector make(CdlNode, std::string, const std::vector<std::string>&, int, const char*[],
3130 std::vector<std::pair<std::string,std::string> >&);
3131 virtual ~CdlProperty_StringVectorBody();
3133 const std::vector<std::string>& get_strings() const;
3134 std::string get_first_string() const;
3135 unsigned int get_number_of_strings() const;
3136 std::string get_string(unsigned int) const;
3137 bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
3138 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3141 typedef CdlPropertyBody inherited;
3143 CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector<std::string>&, int, const char*[],
3144 std::vector<std::pair<std::string,std::string> >&);
3146 std::vector<std::string> data;
3148 CdlProperty_StringVectorBody_Invalid = 0,
3149 CdlProperty_StringVectorBody_Magic = 0x4ed039f3
3150 } cdlproperty_stringvectorbody_cookie;
3152 CdlProperty_StringVectorBody();
3153 CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
3154 CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
3158 //{{{ CdlProperty_Reference
3160 // ----------------------------------------------------------------------------
3161 // This is used for properties such as wizard and dialog, where the data
3162 // identifies some other entity in the system. The class is both a property
3163 // and a reference object. Most of the desired functionality is provided by
3164 // inheritance from CdlReference.
3166 class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
3168 friend class CdlTest;
3171 static CdlProperty_Reference make(CdlNode, std::string /* id */, std::string /* destination */,
3172 CdlUpdateHandler, int, const char*[],
3173 std::vector<std::pair<std::string,std::string> >&);
3174 virtual ~CdlProperty_ReferenceBody();
3176 void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3178 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3179 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3182 typedef CdlPropertyBody inherited_property;
3183 typedef CdlReference inherited_reference;
3185 CdlUpdateHandler update_handler;
3187 CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
3188 std::vector<std::pair<std::string,std::string> >&);
3190 CdlProperty_ReferenceBody_Invalid = 0,
3191 CdlProperty_ReferenceBody_Magic = 0x78100339
3192 } cdlproperty_referencebody_cookie;
3194 CdlProperty_ReferenceBody();
3195 CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
3196 CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
3200 //{{{ CdlProperty_Expression
3202 // ----------------------------------------------------------------------------
3203 // An expression property simply inherits its functionality from the basic
3204 // property class and from the expression class.
3206 class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
3208 friend class CdlTest;
3211 static CdlProperty_Expression make(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
3212 std::vector<std::pair<std::string,std::string> >&);
3213 virtual ~CdlProperty_ExpressionBody();
3214 void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3215 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3216 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3219 typedef CdlPropertyBody inherited_property;
3220 typedef CdlExpressionBody inherited_expression;
3222 CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
3223 std::vector<std::pair<std::string,std::string> >&);
3225 CdlUpdateHandler update_handler;
3227 CdlProperty_ExpressionBody_Invalid = 0,
3228 CdlProperty_ExpressionBody_Magic = 0x05fb4056
3229 } cdlproperty_expressionbody_cookie;
3231 CdlProperty_ExpressionBody();
3232 CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
3233 CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
3237 //{{{ CdlProperty_ListExpression
3239 // ----------------------------------------------------------------------------
3240 // Similarly a list property simply inherits from property and from
3241 // list expressions.
3243 class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
3245 friend class CdlTest;
3248 static CdlProperty_ListExpression make(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
3249 std::vector<std::pair<std::string,std::string> >&);
3250 virtual ~CdlProperty_ListExpressionBody();
3251 void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3252 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3253 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3256 typedef CdlPropertyBody inherited_property;
3257 typedef CdlListExpressionBody inherited_expression;
3259 CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
3260 std::vector<std::pair<std::string,std::string> >&);
3262 CdlUpdateHandler update_handler;
3264 CdlProperty_ListExpressionBody_Invalid = 0,
3265 CdlProperty_ListExpressionBody_Magic = 0x6b0136f5
3266 } cdlproperty_listexpressionbody_cookie;
3268 CdlProperty_ListExpressionBody();
3269 CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
3270 CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
3274 //{{{ CdlProperty_GoalExpression
3276 // ----------------------------------------------------------------------------
3277 // And a goal property inherits from property and from goal expressions.
3279 class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
3281 friend class CdlTest;
3284 static CdlProperty_GoalExpression make(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
3285 std::vector<std::pair<std::string,std::string> >&);
3286 virtual ~CdlProperty_GoalExpressionBody();
3287 void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3288 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3289 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3292 typedef CdlPropertyBody inherited_property;
3293 typedef CdlGoalExpressionBody inherited_expression;
3295 CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
3296 std::vector<std::pair<std::string,std::string> >&);
3298 CdlUpdateHandler update_handler;
3300 CdlProperty_GoalExpressionBody_Invalid = 0,
3301 CdlProperty_GoalExpressionBody_Magic = 0x08b2b31e
3302 } cdlproperty_goalexpressionbody_cookie;
3304 CdlProperty_GoalExpressionBody();
3305 CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
3306 CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
3312 //{{{ CdlParse class
3314 // ----------------------------------------------------------------------------
3315 // This is another utility class for collecting together parsing-related
3318 // Note that this is only a utility class. When libcdl is used for parsing
3319 // things not related to software configuration the new functionality
3320 // does not have to reside inside the CdlParse class, but it may be
3321 // possible to re-use some of the functionality in that class.
3326 // Utility routines.
3327 static std::string get_tcl_cmd_name(std::string);
3328 static std::string concatenate_argv(int, const char*[], int);
3329 static int parse_options(CdlInterpreter, std::string /* diag_prefix */, char** /* options */,
3330 int /* argc */, const char*[] /* argv */, int /* start_index */,
3331 std::vector<std::pair<std::string,std::string> >& /* result */);
3332 static std::string construct_diagnostic(CdlInterpreter, std::string /* classification */,
3333 std::string /* sub-identifier */, std::string /* message */);
3335 static void report_error(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
3336 static void report_warning(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
3337 static void clear_error_count(CdlInterpreter);
3338 static int get_error_count(CdlInterpreter);
3339 static void incr_error_count(CdlInterpreter, int=1);
3341 static std::string get_expression_error_location(void);
3343 // Support for Tcl's "unknown" command
3344 static int unknown_command(CdlInterpreter, int, const char*[]);
3346 // Property-related utilities
3347 static void report_property_parse_error(CdlInterpreter, std::string, std::string);
3348 static void report_property_parse_error(CdlInterpreter, CdlProperty, std::string);
3349 static void report_property_parse_warning(CdlInterpreter, std::string, std::string);
3350 static void report_property_parse_warning(CdlInterpreter, CdlProperty, std::string);
3352 // Utility parsing routines
3353 static int parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
3354 char**, void (*)(CdlInterpreter, CdlProperty_Minimal));
3355 static int parse_string_property(CdlInterpreter, int, const char*[], std::string,
3356 char**, void (*)(CdlInterpreter, CdlProperty_String));
3357 static int parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
3358 char**, void (*)(CdlInterpreter, CdlProperty_TclCode));
3359 static int parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
3360 char**, void (*)(CdlInterpreter, CdlProperty_StringVector),
3361 bool /* allow_empty */ = false);
3362 static int parse_reference_property(CdlInterpreter, int, const char*[], std::string,
3363 char**, void (*)(CdlInterpreter, CdlProperty_Reference),
3364 bool /* allow_empty */,
3366 static int parse_expression_property(CdlInterpreter, int, const char*[], std::string,
3367 char **, void (*)(CdlInterpreter, CdlProperty_Expression),
3369 static int parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
3370 char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
3372 static int parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
3373 char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
3380 // ----------------------------------------------------------------------------
3381 // A node object has a name and lives in a hierarchy. Each node keeps
3382 // track of the toplevel and owner. The memory overheads are
3383 // relatively small compared with the performance gains when such
3384 // information is needed.
3386 // A node object also has a vector of properties, and can be referred to
3387 // by properties in other nodes. Some of the properties may result in
3392 friend class CdlTest;
3394 // Adding and removing nodes from the hierarchy is done
3395 // by CdlToplevel members.
3396 friend class CdlToplevelBody;
3398 // CdlLoadable must be able to access the destructor
3399 friend class CdlLoadableBody;
3401 // It is intended that CdlProperties will also add and remove themselves
3402 friend class CdlPropertyBody;
3404 // CdlReference bind and unbind operations need access to
3405 // the referrers vector. So does CdlTransaction::commit()
3406 friend class CdlReference;
3407 friend class CdlTransactionBody;
3411 // Basic information.
3412 std::string get_name() const;
3413 CdlContainer get_parent() const;
3414 CdlLoadable get_owner() const;
3415 CdlToplevel get_toplevel() const;
3417 // Propagation support. Some updates such as active/inactive changes
3418 // get applied to nodes as well as to properties. Note that because
3419 // of multiple inheritance this virtual call can get confusing.
3420 virtual void update(CdlTransaction, CdlUpdate);
3422 // Is this node active or not? The is_active() call refers
3423 // to the global state, things may be different inside a
3425 bool is_active() const;
3426 bool is_active(CdlTransaction transaction);
3428 // Generally nodes become active when the parent becomes
3429 // active and enabled. Some derived classes may impose
3430 // additional restrictions, for example because of
3431 // active_if constraints. This routine can be used
3432 // to check whether or not a node should become active.
3433 virtual bool test_active(CdlTransaction);
3435 // Provide access to the various properties. Currently all this
3436 // information is publicly available.
3437 const std::vector<CdlProperty>& get_properties() const;
3438 CdlProperty get_property(std::string) const;
3439 void get_properties(std::string, std::vector<CdlProperty>&) const;
3440 std::vector<CdlProperty> get_properties(std::string) const;
3441 bool has_property(std::string) const;
3442 int count_properties(std::string) const;
3444 // Provide access to the various global conflicts. More
3445 // commonly conflicts are accessed on a per-transaction basis.
3446 void get_conflicts(std::vector<CdlConflict>&) const;
3447 void get_conflicts(bool (*)(CdlConflict), std::vector<CdlConflict>&) const;
3448 void get_structural_conflicts(std::vector<CdlConflict>&) const;
3449 void get_structural_conflicts(bool (*)(CdlConflict), std::vector<CdlConflict>&) const;
3451 // Provide access to all the referrers. This may not get used very
3452 // much outside the library itself.
3453 const std::vector<CdlReferrer>& get_referrers() const;
3455 // Add property parsers and validation code appropriate for a
3456 // node. Currently this is a no-op, there are no properties
3457 // associated with every node, but this may change in future e.g.
3458 // for diagnostics purposes.
3459 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
3460 void check_properties(CdlInterpreter);
3462 // Persistence support. The final classes such as cdl_option
3463 // should provide implementations of these functions. The
3464 // base function takes care of data that was present in an
3465 // original save file but which was not recognised.
3467 // Configuration save files are Tcl scripts, so it seems
3468 // appropriate to handle the I/O via the Tcl library and
3469 // to have a TCL interpreter available.
3470 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3471 bool has_additional_savefile_information() const;
3473 // Mainly for diagnostics code, what is the actual name for this
3474 // type of CDL object? This should be in terms of CDL data, e.g.
3475 // "package" or "component", rather than in implementation terms
3476 // such as "CdlPackageBody".
3477 virtual std::string get_class_name() const;
3479 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3480 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3484 // CdlNodeBodies are only instantiated by derived classes.
3485 // They must always have a name. They need not be placed
3486 // in the hierarchy immediately, that can wait until
3488 CdlNodeBody(std::string);
3489 // A dummy constructor is needed because of the virtual
3493 // Nodes cannot be destroyed directly by application code,
3494 // only by higher-level library functions such as unload_package()
3495 virtual ~CdlNodeBody();
3497 // Updating the name is rarely required, but is useful for savefiles.
3498 void set_name(std::string);
3500 // Is the node currently active? This applies to the global state
3501 // only, not per-transaction state. Some derived classes may want
3502 // to override the default value
3507 // The basic data. The name is known during construction.
3508 // The other three fields get updated by e.g. CdlToplevel::add_node();
3510 CdlContainer parent;
3512 CdlToplevel toplevel;
3514 // This is used by remove_node_from_toplevel()/add_node_to_toplevel()
3515 // to allow the latter to exactly reverse the former
3516 int remove_node_container_position;
3518 // Properties normally only get added during the parsing process,
3519 // and only get removed when the object itself is destroyed.
3520 // A vector is the obvious implementation.
3521 std::vector<CdlProperty> properties;
3523 // Currently a vector of referrers is used. This vector is subject
3524 // to change when packages get loaded and unloaded, possibly a
3525 // list would be better.
3526 std::vector<CdlReferrer> referrers;
3528 // Savefiles may contain information that is not recognised by the
3529 // current library, especially because of savefile hooks which
3530 // allow e.g. the configuration tool to store its own information
3531 // in save files. This information must not be lost, even if you are
3532 // e.g. mixing command line and GUI tools. This vector holds
3533 // the savefile information so that it can be put in the next
3535 std::vector<std::string> unsupported_savefile_strings;
3538 CdlNodeBody_Invalid = 0,
3539 CdlNodeBody_Magic = 0x309595b5
3540 } cdlnodebody_cookie;
3542 // Illegal operations
3543 CdlNodeBody(const CdlNodeBody&);
3544 CdlNodeBody& operator=(const CdlNodeBody&);
3550 // ----------------------------------------------------------------------------
3551 // A container is a node that can contain other nodes.
3553 class CdlContainerBody : virtual public CdlNodeBody {
3555 friend class Cdltest;
3557 // Allow CdlNode::check_this() access to the internals
3558 friend class CdlNodeBody;
3560 // Adding a node to the hierarchy is done by a CdlToplevel member.
3561 // Ditto for removing.
3562 friend class CdlToplevelBody;
3564 // Deleting a container can happen inside CdlToplevel and CdlLoadable
3565 friend class CdlLoadableBody;
3569 const std::vector<CdlNode>& get_contents() const;
3570 bool contains(CdlConstNode, bool /* recurse */ = false) const;
3571 bool contains(const std::string, bool /* recurse */ = false) const;
3572 CdlNode find_node(const std::string, bool /* recurse */ = false) const;
3574 // Propagation support. Some updates such as active/inactive changes
3575 // get applied to nodes as well as to properties.
3576 virtual void update(CdlTransaction, CdlUpdate);
3578 // Persistence support.
3579 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3581 virtual std::string get_class_name() const;
3582 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3583 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3587 // Containers cannot be destroyed explicitly, only via higher-level
3588 // code such as unload_package();
3589 virtual ~CdlContainerBody();
3592 // Special constructor needed for internal use.
3593 CdlContainerBody(std::string);
3595 // The CdlToplevel class needs access to its own contents.
3596 std::vector<CdlNode> contents;
3600 CdlContainerBody_Invalid = 0,
3601 CdlContainerBody_Magic = 0x543c5f1d
3602 } cdlcontainerbody_cookie;
3604 // Illegal operations
3605 CdlContainerBody(const CdlContainerBody&);
3606 CdlContainerBody& operator=(const CdlContainerBody&);
3612 // ----------------------------------------------------------------------------
3613 // A loadable object is a container that gets loaded or unloaded
3614 // atomically from a toplevel. The key difference is that a loadable
3615 // keeps track of all nodes that were loaded as part of this
3616 // operation, thus allowing unload operations to happen safely even if
3617 // nodes get re-parented all over the hierarchy. In addition, there is
3618 // a slave interpreter associated with every loadable.
3620 class CdlLoadableBody : virtual public CdlContainerBody {
3622 friend class CdlTest;
3624 // Allow CdlNode::check_this() access to the internals
3625 friend class CdlNodeBody;
3627 // Adding nodes to the hierarchy is done by a toplevel member
3628 friend class CdlToplevelBody;
3631 virtual ~CdlLoadableBody();
3634 const std::vector<CdlNode>& get_owned() const;
3635 bool owns(CdlConstNode) const;
3636 CdlInterpreter get_interpreter() const;
3637 std::string get_directory() const;
3639 // Some properties such as doc and compile reference filenames.
3640 // A search facility is useful.
3641 virtual std::string find_relative_file(std::string /* filename */, std::string /* directory */ = "") const;
3642 virtual std::string find_absolute_file(std::string, std::string, bool /* allow_urls */ = false) const;
3643 virtual bool has_subdirectory(std::string) const;
3645 // These support load/unload operations inside transactions
3646 // They are static members because some of them will want
3647 // to delete the loadable.
3648 static void transaction_commit_load(CdlTransaction, CdlLoadable);
3649 static void transaction_cancel_load(CdlTransaction, CdlLoadable);
3650 static void transaction_commit_unload(CdlTransaction, CdlLoadable);
3651 static void transaction_cancel_unload(CdlTransaction, CdlLoadable);
3653 // Binding and unbinding of properties. This involves processing
3654 // the various properties, calculating default values, etc.
3655 void bind(CdlTransaction);
3656 void unbind(CdlTransaction);
3658 virtual std::string get_class_name() const;
3659 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3660 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3664 CdlLoadableBody(CdlToplevel, std::string /* directory */);
3666 // Needed by derived classes, but not actually used.
3671 std::vector<CdlNode> owned;
3672 CdlInterpreter interp;
3673 std::string directory;
3675 // Used by add/remove_node_from_toplevel()
3676 int remove_node_loadables_position;
3679 CdlLoadableBody_Invalid = 0,
3680 CdlLoadableBody_Magic = 0x488d6127
3681 } cdlloadablebody_cookie;
3683 // Invalid operations
3684 CdlLoadableBody(const CdlLoadableBody&);
3685 CdlLoadableBody& operator=(const CdlLoadableBody&);
3691 // ----------------------------------------------------------------------------
3692 // Toplevels are containers that live at the top of a hierarchy
3693 // (surprise surprise). This means that they do not have a parent.
3694 // In addition a toplevel object keeps track of all the names
3695 // used, guaranteeing uniqueness and providing a quick lookup
3698 // Every container is also a node, so every toplevel is a node.
3699 // Inheritance from CdlNode may seem wrong. However it achieves
3700 // consistency, everything in the hierarchy including the toplevel
3701 // is a node. The main disadvantage is that every toplevel now
3704 class CdlToplevelBody : virtual public CdlContainerBody {
3706 friend class CdlTest;
3708 // Allow CdlNode::check_this() access to the internals
3709 friend class CdlNodeBody;
3711 // The CdlTransaction class needs direct access to the lists
3713 friend class CdlTransactionBody;
3716 virtual ~CdlToplevelBody();
3718 // Updating the hierarchy. This happens a node at a time. Adding a
3719 // node involves updating the name->node map in the toplevel,
3720 // setting the node's parent/owner/toplevel fields, and updating
3721 // the parent and owner containers. The owner may be 0 for special
3722 // nodes such as the orphans container. The parent must be known,
3723 // although it may change later on during a change_parent() call.
3725 // Removing a node is more complicated, and involves a two-stage
3726 // process. First the node is removed from the toplevel, thus
3727 // eliminating the name->node mapping. The owner and parent fields
3728 // are preserved at this stage (except for the loadable itself),
3729 // and the operation may be undone if the relevant transaction
3730 // gets cancelled. If the transaction gets committed then the
3731 // second remove operation handles the owner and parent fields,
3732 // just prior to the node being deleted. For convenience there
3733 // are also per-loadable variants for some of these.
3735 // change_parent() is used to support parent-properties.
3736 // A container of 0 indicates an orphan, i.e. a parent
3737 // property that did not or does not correspond to a
3738 // current container.
3740 // There is also a clean-up call. This gets used for interfaces
3741 // which may alternate between belonging to a loadable and
3742 // being auto-created.
3743 void add_node(CdlLoadable, CdlContainer, CdlNode);
3744 void add_node_to_toplevel(CdlNode);
3745 void remove_node_from_toplevel(CdlNode);
3746 static void remove_node(CdlLoadable, CdlContainer, CdlNode);
3747 void add_loadable_to_toplevel(CdlLoadable);
3748 void remove_loadable_from_toplevel(CdlLoadable);
3749 void change_parent(CdlLoadable, CdlContainer /* current */, CdlContainer /* new */, CdlNode, int /* pos */ = -1);
3750 void cleanup_orphans();
3752 // Toplevels keep track of all the loadables, in addition to
3753 // inheriting tree behaviour from CdlContainer. This is convenient
3754 // for some operations like determining build information
3755 // which must operate on a per-loadable basis.
3756 const std::vector<CdlLoadable>& get_loadables() const;
3758 // Name uniqueness is guaranteed. It is convenient to have an STL
3759 // map as a lookup service.
3760 CdlNode lookup(const std::string) const;
3762 // There are two conflict lists associated with each toplevel. One
3763 // is for "structural" conflicts, ones that can only be resolved
3764 // by a fairly major change such as loading another package: a
3765 // typical example is an unresolved parent reference. The other is
3766 // for conflicts that can probably be resolved simply by changing
3767 // some values. Both sets of conflicts are held as a simple list.
3769 // The active vs. inactive state of a CDL entity affects the
3770 // location of structural vs. non-structural conflicts. If an
3771 // entity becomes inactive then structural conflicts are not
3772 // affected, but non-structural conflicts are removed from the
3773 // global list. If an entity's "requires" expression is not
3774 // satisfied but the entity is inactive anyway then this is
3776 const std::list<CdlConflict>& get_all_conflicts() const;
3777 const std::list<CdlConflict>& get_all_structural_conflicts() const;
3779 // Try to resolve some or all conflicts. Typically a new transaction
3780 // will be created for this.
3781 void resolve_conflicts(const std::vector<CdlConflict>&);
3782 void resolve_all_conflicts();
3784 // Toplevels can have descriptions provided by the user. This is
3785 // particularly important for pre-defined templates, target
3786 // board descriptions, etc. where the user would like some
3787 // extra information about the template before loading it in.
3788 // The default value is an empty string.
3789 std::string get_description() const;
3790 void set_description(std::string);
3792 // Each toplevel must have an associated master Tcl interpreter.
3793 CdlInterpreter get_interpreter() const;
3795 // Each toplevel should also have an associated directory for
3796 // the component repository. It is not required that all loadables
3797 // are relative to this, but that is the default behaviour.
3798 std::string get_directory() const;
3800 // Each toplevel may have a single active main transaction.
3801 // For now there is no support for concurrent transactions
3802 // operating on a single toplevel (although nested transactions
3804 CdlTransaction get_active_transaction() const;
3806 // Build and define operations are available for all toplevels,
3807 // even if they are not always applicable
3808 void get_build_info(CdlBuildInfo&);
3809 void get_all_build_info(CdlBuildInfo&);
3810 void generate_config_headers(std::string);
3811 void get_config_headers(std::vector<std::string>&);
3812 void generate_build_tree(std::string, std::string = "");
3814 // Values can be stored in limbo. This is useful when unloading
3815 // and reloading packages, e.g. when changing a version the
3816 // current settings can be preserved as much as possible.
3817 void set_limbo_value(CdlValuable);
3818 bool has_limbo_value(std::string) const;
3819 CdlValue get_limbo_value(std::string) const;
3820 CdlValue get_and_remove_limbo_value(std::string);
3823 // Persistence support. These are commented in the source code.
3824 void initialize_savefile_support();
3825 static bool savefile_support_initialized();
3826 void add_savefile_command(std::string, CdlSaveCallback, CdlInterpreterCommand);
3827 void add_savefile_subcommand(std::string, std::string, CdlSaveCallback, CdlInterpreterCommand);
3828 void get_savefile_commands(std::vector<CdlInterpreterCommandEntry>&);
3829 void get_savefile_subcommands(std::string, std::vector<CdlInterpreterCommandEntry>&);
3830 void save_command_details(CdlInterpreter, Tcl_Channel, int, bool);
3831 static int savefile_handle_command(CdlInterpreter, int, const char*[]);
3832 static int savefile_handle_unsupported(CdlInterpreter, int, const char*[]);
3833 static int savefile_handle_unknown(CdlInterpreter, int, const char*[]);
3834 void save_unsupported_commands(CdlInterpreter, Tcl_Channel, int, bool);
3835 static cdl_int get_library_savefile_version();
3836 static int savefile_handle_version(CdlInterpreter, int, const char*[]);
3837 static cdl_int get_savefile_version(CdlInterpreter);
3838 void save_conflicts(CdlInterpreter, Tcl_Channel, int, bool);
3839 static void save_separator(CdlInterpreter, Tcl_Channel, std::string, bool);
3841 virtual std::string get_class_name() const;
3842 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3843 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3846 CdlToplevelBody(CdlInterpreter, std::string);
3850 std::map<std::string,CdlNode> lookup_table;
3851 std::vector<CdlLoadable> loadables;
3852 std::map<std::string,CdlValue> limbo;
3853 CdlInterpreter interp;
3854 CdlContainer orphans;
3855 std::string description;
3856 std::string directory;
3857 std::list<CdlConflict> conflicts;
3858 std::list<CdlConflict> structural_conflicts;
3860 // The savefile support corresponding to this application.
3861 static cdl_int savefile_version;
3862 static bool savefile_commands_initialized;
3863 static std::vector<CdlSavefileCommand> savefile_commands;
3864 static std::map<std::string,std::vector<CdlSavefileCommand> > savefile_subcommands;
3866 // Per-toplevel support. A savefile may contain unrecognised
3867 // commands at the toplevel of a file, as well as unrecognised
3868 // commands in e.g. the body of a cdl_configuration command.
3869 // The latter is handled via the CdlNode base class.
3870 std::vector<std::string> unsupported_savefile_toplevel_strings;
3871 std::vector<std::string> unsupported_savefile_commands;
3872 std::map<std::string, std::vector<std::string> > unsupported_savefile_subcommands;
3874 // Keep track of the current active transaction for this toplevel (if any)
3875 CdlTransaction transaction;
3878 CdlToplevelBody_Invalid = 0,
3879 CdlToplevelBody_Magic = 0x0834666e
3880 } cdltoplevelbody_cookie;
3882 // Invalid operations
3883 CdlToplevelBody(const CdlToplevelBody&);
3884 CdlToplevelBody& operator=(const CdlToplevelBody&);
3888 //{{{ CdlUserVisible
3890 // ----------------------------------------------------------------------------
3891 // A user-visible object is likely to have properties such as display,
3892 // description and doc. Many user-visible objects will have values but
3893 // not all, for example custom dialogs are likely to have a doc
3894 // property but they do not have a value.
3896 class CdlUserVisibleBody : virtual public CdlNodeBody {
3898 friend class CdlTest;
3901 virtual ~CdlUserVisibleBody();
3903 std::string get_display() const;
3904 std::string get_description() const;
3905 std::string get_doc() const;
3907 // NOTE: this will only work for absolute doc strings or for doc
3908 // strings that are relative to the package.
3909 std::string get_doc_url() const;
3911 // Add property parsers and validation code appropriate for a
3912 // user-visible object such as doc and description
3913 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
3914 void check_properties(CdlInterpreter);
3915 static int parse_description(CdlInterpreter, int, const char*[]);
3916 static int parse_display(CdlInterpreter, int, const char*[]);
3917 static int parse_doc(CdlInterpreter, int, const char*[]);
3919 // Persistence support. The save code simply outputs some comments
3920 // corresponding to the display, doc and description properties.
3921 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3923 virtual std::string get_class_name() const;
3924 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3925 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3928 CdlUserVisibleBody();
3933 CdlUserVisibleBody_Invalid = 0,
3934 CdlUserVisibleBody_Magic = 0x13bbc817
3935 } cdluservisiblebody_cookie;
3937 // Illegal operations
3938 CdlUserVisibleBody(const CdlUserVisibleBody&);
3939 CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
3945 // ----------------------------------------------------------------------------
3946 // A parentable object may have the parent property, redefining its
3947 // position in the hierarchy.
3949 class CdlParentableBody : virtual public CdlNodeBody {
3951 friend class CdlTest;
3954 virtual ~CdlParentableBody();
3956 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
3957 void check_properties(CdlInterpreter);
3958 static int parse_parent(CdlInterpreter, int, const char*[]);
3959 static void update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
3961 virtual std::string get_class_name() const;
3962 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3963 CYGDBG_DECLARE_MEMLEAK_COUNTER();
3966 CdlParentableBody();
3970 // Unloads may be cancelled. To restore the previous state exactly
3971 // it is necessary to keep track of the old position.
3972 int change_parent_save_position;
3975 CdlParentableBody_Invalid = 0,
3976 CdlParentableBody_Magic = 0x40c6a077
3977 } cdlparentablebody_cookie;
3979 // Illegal operations
3980 CdlParentableBody(const CdlParentableBody&);
3981 CdlParentableBody& operator=(const CdlParentableBody&);
3987 // ----------------------------------------------------------------------------
3988 // A valuable body has a value. Many valuables can be modified but not all.
3989 // Some properties make a valuable object read-only. In future there is
3990 // likely to be support for locked values as well. There is a member function
3991 // to check whether or not a valuable object is modifiable.
3993 // Relevant properties for a valuable object are:
3995 // 1) flavor - readily available via CdlValue::get_flavor()
3996 // 2) default_value - an expression
3997 // 3) legal_values - a list expression
3998 // 4) entry_proc - for validation purposes, in addition to legal_values
3999 // 5) check_proc - ditto
4000 // 6) active_if - goal expression
4001 // 7) requires - goal expression
4002 // 8) dialog - a custom dialog for editing this value
4003 // 9) calculated - non-modifiable
4004 // 10) implements - for interfaces
4006 // A CdlValuable does not inherit directly from CdlValue, since it should
4007 // not be possible to modify a Valuable directly. Instead it contains a
4008 // CdlValue member, and provides essentially the same functions as
4011 class CdlValuableBody : virtual public CdlNodeBody {
4013 friend class CdlTest;
4015 // Transaction commit operations require direct access to the CdlValue
4016 friend class CdlTransactionBody;
4022 virtual ~CdlValuableBody();
4024 // Accessing the current value. There are variants for the global state
4025 // and for per-transaction operations.
4026 const CdlValue& get_whole_value() const;
4028 CdlValueFlavor get_flavor() const;
4029 CdlValueFlavor get_flavor(CdlTransaction transaction) const
4030 { // The transaction is irrelevant, it cannot change the flavor
4031 return this->get_flavor();
4034 CdlValueSource get_source() const;
4035 bool has_source( CdlValueSource) const;
4036 bool is_enabled( CdlValueSource = CdlValueSource_Current) const;
4037 std::string get_value( CdlValueSource = CdlValueSource_Current) const;
4038 bool has_integer_value( CdlValueSource = CdlValueSource_Current) const;
4039 cdl_int get_integer_value( CdlValueSource = CdlValueSource_Current) const;
4040 bool has_double_value( CdlValueSource = CdlValueSource_Current) const;
4041 double get_double_value( CdlValueSource = CdlValueSource_Current) const;
4042 CdlSimpleValue get_simple_value( CdlValueSource = CdlValueSource_Current) const;
4044 CdlValueSource get_source(CdlTransaction) const;
4045 bool has_source( CdlTransaction, CdlValueSource) const;
4046 bool is_enabled( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4047 std::string get_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4048 bool has_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4049 cdl_int get_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4050 bool has_double_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4051 double get_double_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4052 CdlSimpleValue get_simple_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4054 // -----------------------------------------------------------------
4055 // Modify access. There are two variants of all the functions:
4057 // 1) no transaction argument. A transaction will be created,
4058 // committed, and destroyed for the change in question.
4060 // 2) a transaction argument. The existing transaction will be
4061 // updated but not committed. This allows multiple changes
4062 // to be grouped together.
4064 // There are only a handful of exported functions, but lots
4065 // of inline variants.
4066 void set_source(CdlValueSource);
4067 void invalidate_source(CdlValueSource);
4068 void set_enabled(bool, CdlValueSource);
4069 void set_value(CdlSimpleValue&, CdlValueSource);
4070 void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
4071 void set(CdlSimpleValue&, CdlValueSource);
4073 void set_source(CdlTransaction, CdlValueSource);
4074 void invalidate_source(CdlTransaction, CdlValueSource);
4075 void set_enabled(CdlTransaction, bool, CdlValueSource);
4076 void set_value(CdlTransaction, CdlSimpleValue&, CdlValueSource);
4077 void set_enabled_and_value(CdlTransaction, bool, CdlSimpleValue&, CdlValueSource);
4078 void set(CdlTransaction, CdlSimpleValue&, CdlValueSource);
4079 void set(CdlTransaction, const CdlValue&);
4081 void enable(CdlValueSource source)
4083 set_enabled(true, source);
4085 void disable(CdlValueSource source)
4087 set_enabled(false, source);
4089 void set_value(std::string data, CdlValueSource source)
4091 CdlSimpleValue val(data);
4092 set_value(val, source);
4094 void set_integer_value(cdl_int data, CdlValueSource source)
4096 CdlSimpleValue val(data);
4097 set_value(val, source);
4099 void set_double_value(double data, CdlValueSource source)
4101 CdlSimpleValue val(data);
4102 set_value(val, source);
4104 void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
4106 CdlSimpleValue val(data);
4107 set_enabled_and_value(enabled, val, source);
4109 void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
4111 CdlSimpleValue val(data);
4112 set_enabled_and_value(enabled, val, source);
4114 void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
4116 CdlSimpleValue val(data);
4117 set_enabled_and_value(enabled, val, source);
4119 void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4121 set_enabled_and_value(true, val, source);
4123 void enable_and_set_value(std::string data, CdlValueSource source)
4125 set_enabled_and_value(true, data, source);
4127 void enable_and_set_value(cdl_int data, CdlValueSource source)
4129 set_enabled_and_value(true, data, source);
4131 void enable_and_set_value(double data, CdlValueSource source)
4133 set_enabled_and_value(true, data, source);
4135 void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4137 set_enabled_and_value(false, val, source);
4139 void disable_and_set_value(std::string data, CdlValueSource source)
4141 set_enabled_and_value(false, data, source);
4143 void disable_and_set_value(cdl_int data, CdlValueSource source)
4145 set_enabled_and_value(false, data, source);
4147 void disable_and_set_value(double data, CdlValueSource source)
4149 set_enabled_and_value(false, data, source);
4151 void enable(CdlTransaction transaction, CdlValueSource source)
4153 set_enabled(transaction, true, source);
4155 void disable(CdlTransaction transaction, CdlValueSource source)
4157 set_enabled(transaction, false, source);
4159 void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4161 CdlSimpleValue val(data);
4162 set_value(transaction, val, source);
4164 void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4166 CdlSimpleValue val(data);
4167 set_value(transaction, val, source);
4169 void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
4171 CdlSimpleValue val(data);
4172 set_value(transaction, val, source);
4174 void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
4176 CdlSimpleValue val(data);
4177 set_enabled_and_value(transaction, enabled, val, source);
4179 void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
4181 CdlSimpleValue val(data);
4182 set_enabled_and_value(transaction, enabled, val, source);
4184 void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
4186 CdlSimpleValue val(data);
4187 set_enabled_and_value(transaction, enabled, val, source);
4189 void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4191 set_enabled_and_value(transaction, true, val, source);
4193 void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4195 set_enabled_and_value(transaction, true, data, source);
4197 void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4199 set_enabled_and_value(transaction, true, data, source);
4201 void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4203 set_enabled_and_value(transaction, true, data, source);
4205 void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4207 set_enabled_and_value(transaction, false, val, source);
4209 void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4211 set_enabled_and_value(transaction, false, data, source);
4213 void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4215 set_enabled_and_value(transaction, false, data, source);
4217 void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4219 set_enabled_and_value(transaction, false, data, source);
4222 // -----------------------------------------------------------------
4223 virtual bool is_modifiable() const;
4224 void get_widget_hint(CdlWidgetHint&);
4226 // -----------------------------------------------------------------
4227 // Propagation support. If a valuable becomes active or inactive
4228 // because e.g. its parent is disabled then this may affect
4229 // requires conflicts etc.
4230 virtual void update(CdlTransaction, CdlUpdate);
4232 virtual bool test_active(CdlTransaction);
4234 // -----------------------------------------------------------------
4235 // Property-related stuff.
4236 bool has_calculated_expression() const;
4237 bool has_default_value_expression() const;
4238 bool has_legal_values() const;
4239 bool has_entry_proc() const;
4240 bool has_check_proc() const;
4241 bool has_active_if_conditions() const;
4242 bool has_requires_goals() const;
4243 bool has_dialog() const;
4244 bool has_wizard() const;
4246 CdlProperty_Expression get_calculated_expression() const;
4247 CdlProperty_Expression get_default_value_expression() const;
4248 CdlProperty_ListExpression get_legal_values() const;
4249 cdl_tcl_code get_entry_proc() const;
4250 cdl_tcl_code get_check_proc() const;
4251 void get_active_if_conditions(std::vector<CdlProperty_GoalExpression>&) const;
4252 void get_requires_goals(std::vector<CdlProperty_GoalExpression>&) const;
4253 CdlDialog get_dialog() const;
4254 CdlWizard get_wizard() const;
4255 void get_implemented_interfaces(std::vector<CdlInterface>&) const;
4257 // Add property parsers and validation code appropriate for a
4258 // valuable object such as default_value and legal_values
4259 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
4260 void check_properties(CdlInterpreter);
4261 static int parse_active_if(CdlInterpreter, int, const char*[]);
4262 static void active_if_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4263 static int parse_calculated(CdlInterpreter, int, const char*[]);
4264 static void calculated_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4265 static int parse_check_proc(CdlInterpreter, int, const char*[]);
4266 static int parse_default_value(CdlInterpreter, int, const char*[]);
4267 static void default_value_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4268 static int parse_dialog(CdlInterpreter, int, const char*[]);
4269 static void dialog_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4270 static int parse_entry_proc(CdlInterpreter, int, const char*[]);
4271 static int parse_flavor(CdlInterpreter, int, const char*[]);
4272 static int parse_group(CdlInterpreter, int, const char*[]);
4273 static int parse_implements(CdlInterpreter, int, const char*[]);
4274 static void implements_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4275 static int parse_legal_values(CdlInterpreter, int, const char*[]);
4276 static void legal_values_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4277 static int parse_requires(CdlInterpreter, int, const char*[]);
4278 static void requires_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4279 static int parse_wizard(CdlInterpreter, int, const char*[]);
4280 static void wizard_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4282 // Persistence suppot
4283 void save(CdlInterpreter, Tcl_Channel, int, bool /* modifiable */, bool /* minimal */);
4284 bool value_savefile_entry_needed() const;
4285 static void initialize_savefile_support(CdlToplevel, std::string);
4286 static int savefile_value_source_command(CdlInterpreter, int, const char*[]);
4287 static int savefile_user_value_command(CdlInterpreter, int, const char*[]);
4288 static int savefile_wizard_value_command(CdlInterpreter, int, const char*[]);
4289 static int savefile_inferred_value_command(CdlInterpreter, int, const char*[]);
4290 static int savefile_xxx_value_command(CdlInterpreter, int, const char*[], CdlValueSource);
4292 // Make sure that the current value is legal. This gets called automatically
4293 // by all the members that modify values. It has to be a virtual function
4294 // since some derived classes, e.g. hardware-related valuables, may impose
4295 // constraints over and above legal_values etc.
4296 virtual void check_value(CdlTransaction);
4298 // Similarly check the requires properties
4299 void check_requires(CdlTransaction, CdlProperty_GoalExpression);
4300 void check_requires(CdlTransaction);
4302 // Enabling or disabling a valuable may affect the active state of children
4303 void check_children_active(CdlTransaction);
4305 virtual std::string get_class_name() const;
4306 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
4307 CYGDBG_DECLARE_MEMLEAK_COUNTER();
4310 CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
4317 CdlValuableBody_Invalid = 0,
4318 CdlValuableBody_Magic = 0x2b2acc03
4319 } cdlvaluablebody_cookie;
4321 // Illegal operations
4322 CdlValuableBody(const CdlValuableBody&);
4323 CdlValuableBody& operator=(const CdlValuableBody&);
4327 //{{{ CdlTransaction etc.
4331 // ----------------------------------------------------------------------------
4332 // Transactions. These are used for all changes to a configuration. In some
4333 // cases a transaction is implicit:
4335 // valuable->set_value(...)
4337 // The actual implementation of this is:
4339 // valuable->set_value(...)
4340 // transact = CdlTransactionBody::make(valuable->get_toplevel())
4341 // valuable->set_value(transact, ...)
4342 // <complicated bits>
4343 // transact->commit()
4346 // Alternatively the use of transactions may be explicit. For implicit
4347 // uses the library will invoke an inference callback at the
4348 // appropriate time. For explicit transactions this is not necessary.
4350 // The commit() operation invokes a transaction callback which should
4351 // not be confused with the inference callback. The former is intended
4352 // for display updates, it specifies everything that has changed
4353 // during the transaction. The latter is used for reporting new
4354 // conflicts to the user, suggesting fixes, etc.
4356 // A whole bunch of information is associated with a transaction,
4357 // including: all value changes, details of new conflicts, and details
4358 // of existing conflicts that have gone away. The commit operation
4359 // takes care of updating the toplevel. Until the commit happens
4360 // the toplevel itself remains unchanged. It is also possible to cancel
4363 // An important concept related to transactions is propagation.
4364 // Changing a value may have various effects, for example it may
4365 // change the result of a legal_values list expression, resulting in a
4366 // conflict object having to be created or destroyed. Changing one
4367 // value may result in other value changes, e.g. because of a
4368 // default_value property. All this is "propagation", and may
4369 // happen multiple times within a single transaction.
4371 // Transaction objects are also used during load or unload operations,
4372 // but those are a little bit special. In particular it is not possible
4373 // to cancel such a transaction, there will have been updates to the
4374 // toplevel. Using a transaction is convenient because there is a
4375 // need for propagation.
4377 // Currently a transaction should be deleted immediately after a
4378 // commit or cancel. This may change in future, in that transaction
4379 // objects can be used to hold undo information.
4382 // The other big concept related to transactions is inference.
4383 // Changing a value may result in one or more new conflicts being
4384 // created. In some cases the library can figure out for itself how to
4385 // resolve these conflicts, using an inference engine. There are
4386 // parameters to control the operation of the inference engine,
4387 // including whether it runs at all, what changes it is allowed
4388 // to make automatically (usually default and inferred values can
4389 // be updated, but not wizard or user values), and how much
4390 // recursion will happen.
4392 // Assuming a default setup in a GUI environment, a typical
4393 // sequence of events would be:
4395 // valuable->set_value(...)
4396 // transact = CdlTransactionBody::make(valuable->get_toplevel())
4397 // valuable->set_value(transact, ...)
4398 // transact->set_whole_value(valuable, ...)
4399 // transact->propagate()
4400 // while (!finished)
4401 // transact->resolve()
4403 // invoke inference callback
4404 // transact->apply_solution() (1 or more times)
4405 // transact->set_whole_value(valuable, ...) (1 or more times)
4406 // transact->propagate()
4407 // transact->commit() | transact->cancel()
4410 // Note that the propagation steps have to be invoked explicitly,
4411 // allowing multiple changes to be processed in one go. There is
4412 // a utility function which combines the functionality from
4413 // the first propagate() call up to but not including the
4414 // transaction delete operator.
4417 // The inference engine itself is a complicated beast. There are
4418 // a number of interfaces, but at the end of the day it ends up
4419 // creating a sub-transaction and trying to resolve a single
4420 // conflict in that sub-transaction. The conflict may belong to
4421 // the current transaction or it may be global.
4424 // for each conflict of interest
4425 // make sure that there is not already a valid solution
4426 // check that the inference engine can handle it
4427 // create a sub-transaction, associated with the conflict
4428 // apply the conflict resolution code
4429 // if the solution is ok
4431 // else if the solution might e.g. overwrite a user value
4432 // keep it, the user can decide during the inference callback
4434 // The conflict resolution typically works by attempting to change
4435 // one or more values in the sub-transaction, propagating them,
4436 // and seeing what new conflicts get created. If no new conflicts
4437 // get created and one or more existing conflicts go away, groovy.
4438 // Otherwise recursion can be used to try to resolve the new
4439 // conflicts, or other strategies can be explored.
4441 // NOTE: what is really necessary is some way of keeping track of the
4442 // "best" solution to date, and allow exploration of alternatives.
4443 // Or possibly keep track of all solutions. That has to be left to
4444 // a future version.
4447 //{{{ CdlTransactionCommitCancelOp
4449 // ----------------------------------------------------------------------------
4450 // The CdlTransaction class has built-in knowledge of how to handle values,
4451 // active state, and a few things like that. However there are also more
4452 // complicated operations such as loading and unloading, instantiating
4453 // items, etc. which also need to happen in the context of a transaction
4454 // but which the transaction class does not necessarily know about
4455 // itself - or at least, not in any detail. Since the libcdl core is
4456 // intended to be useful in various contexts, some sort of extensibility
4459 // This is achieved by an auxiliary class, CdlTransactionCommitCancelOp.
4460 // Clients of the transaction class can have their own utility class
4461 // which derives from this, and create suitable objects. The transaction
4462 // class maintains a vector of the pending commit/cancel operations.
4464 // Each CdlTransactionCommitCancelOp object has two member functions,
4465 // one for when the transaction gets committed and one for when it
4466 // gets cancelled. If a sub-transaction gets committed then its
4467 // pending ops are transferred across to the parent, allowing the
4468 // parent to be cancelled sensibly: the commit ops only get run for
4469 // the toplevel transaction. If a sub-transaction gets cancelled then
4470 // the pending ops are invoked immediately.
4472 // There is an assumption that commit/cancel ops get executed strictly
4473 // in FIFO order. Specifically, commit ops get run from first one to
4474 // the last one, allowing later operations in the transaction to
4475 // overwrite earlier ones. Cancel ops get run in reverse order.
4477 class CdlTransactionCommitCancelOp {
4478 friend class CdlTest;
4482 CdlTransactionCommitCancelOp() { }
4483 virtual ~CdlTransactionCommitCancelOp() { };
4485 // The default implementations of both of these do nothing.
4486 // Derived classes should override at least one of these
4488 virtual void commit(CdlTransaction transaction) {
4489 CYG_UNUSED_PARAM(CdlTransaction, transaction);
4491 virtual void cancel(CdlTransaction transaction) {
4492 CYG_UNUSED_PARAM(CdlTransaction, transaction);
4501 //{{{ CdlTransaction class
4503 class CdlTransactionBody {
4505 friend class CdlTest;
4507 friend class CdlConflictBody;
4508 friend class CdlValuableBody;
4512 // Create a toplevel transaction
4513 static CdlTransaction make(CdlToplevel);
4514 virtual ~CdlTransactionBody();
4515 CdlToplevel get_toplevel() const;
4517 // Or a sub-transaction. Usually these are created in the context of
4518 // a conflict that is being resolved.
4519 CdlTransaction make(CdlConflict = 0);
4520 CdlTransaction get_parent() const;
4521 CdlConflict get_conflict() const;
4523 // Commit all the changes. Essentially this means transferring
4524 // all of the per-transaction data to the toplevel, and then
4525 // invoking the transaction callback. All propagation, inference,
4526 // etc. should happen before the commit()
4527 // This routine can also be used to transfer changes from a
4528 // sub-transaction to the parent.
4531 // A variant of the commit() operation can be used to
4532 // store a sub-transaction in a conflict's solution vector,
4533 // rather than updating the parent transaction. This is useful
4534 // for inferred solutions which cannot be applied without
4535 // user confirmation
4536 void save_solution();
4538 // Can a solution held in a sub-transaction be applied without
4539 // e.g. overwriting a user value with an inferred value?
4540 bool user_confirmation_required() const;
4542 // If the user has explicitly changed a value in the current transaction
4543 // then the inference engine should not undo this or suggest a solution
4544 // that will undo the change.
4545 bool changed_by_user(CdlValuable) const;
4547 // A variant which is used for checking the hierarchy when disabling
4549 bool subnode_changed_by_user(CdlContainer) const;
4551 // Is one transaction preferable to another?
4552 bool is_preferable_to(CdlTransaction) const;
4554 // Find out about per-transaction conflicts. This is particularly
4555 // useful for the inference callback. The other containers can
4556 // be accessed as well, for completeness.
4557 const std::list<CdlConflict>& get_new_conflicts() const;
4558 const std::list<CdlConflict>& get_new_structural_conflicts() const;
4559 const std::vector<CdlConflict>& get_deleted_conflicts() const;
4560 const std::vector<CdlConflict>& get_deleted_structural_conflicts() const;
4561 const std::vector<CdlConflict>& get_resolved_conflicts() const ;
4562 const std::list<CdlConflict>& get_global_conflicts_with_solutions() const;
4563 const std::map<CdlValuable, CdlValue>& get_changes() const;
4564 const std::set<CdlNode>& get_activated() const;
4565 const std::set<CdlNode>& get_deactivated() const;
4566 const std::set<CdlValuable>& get_legal_values_changes() const;
4568 // Manipulate the current set of conflicts, allowing for nested
4569 // transactions and toplevel conflicts as well.
4570 void clear_conflict(CdlConflict);
4571 bool has_conflict_been_cleared(CdlConflict);
4573 bool has_conflict(CdlNode, bool (*)(CdlConflict));
4574 CdlConflict get_conflict(CdlNode, bool (*)(CdlConflict));
4575 void get_conflicts(CdlNode, bool (*)(CdlConflict), std::vector<CdlConflict>&);
4576 void clear_conflicts(CdlNode, bool (*)(CdlConflict));
4577 bool has_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4578 CdlConflict get_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4579 void get_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector<CdlConflict>&);
4580 void clear_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
4582 bool has_structural_conflict(CdlNode, bool (*)(CdlConflict));
4583 CdlConflict get_structural_conflict(CdlNode, bool (*)(CdlConflict));
4584 void get_structural_conflicts(CdlNode, bool (*)(CdlConflict), std::vector<CdlConflict>&);
4585 void clear_structural_conflicts(CdlNode, bool (*)(CdlConflict));
4586 bool has_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4587 CdlConflict get_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4588 void get_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector<CdlConflict>&);
4589 void clear_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
4591 // During the inference callback the user may decide to
4592 // apply one or more of the solutions.
4593 void apply_solution(CdlConflict);
4594 void apply_solutions(const std::vector<CdlConflict>&);
4595 void apply_all_solutions();
4597 // Cancel all the changes done in this transaction. Essentially
4598 // this just involves clearing out all the STL containers.
4601 // Support for commit/cancel ops. These are used for
4602 // e.g. load and unload operations.
4603 void add_commit_cancel_op(CdlTransactionCommitCancelOp *);
4604 void cancel_last_commit_cancel_op();
4605 CdlTransactionCommitCancelOp* get_last_commit_cancel_op() const;
4606 const std::vector<CdlTransactionCommitCancelOp*>& get_commit_cancel_ops() const;
4608 // Propagation support
4609 void add_active_change(CdlNode);
4610 void add_legal_values_change(CdlValuable);
4612 bool is_propagation_required() const;
4614 // Inference engine support.
4615 void resolve(int = 0); // Process the new conflicts raised by this transaction
4616 void resolve(CdlConflict, int = 0);
4617 void resolve(const std::vector<CdlConflict>&, int = 0);
4619 // An auxiliary function called by the inference engine to perform recursion
4620 bool resolve_recursion(int);
4622 // This function combines propagation, inference, and commit
4623 // in one easy-to-use package
4627 // There is a call to get hold of a CdlValue reference. Modifications
4628 // should happen via a sequence of the form:
4630 // valuable->set_value(transact, ...)
4631 // const CdlValue& old_value = transact->get_whole_value(CdlValuable);
4632 // CdlValue new_value = old_value;
4633 // <modify new_value>
4634 // transact->set_whole_value(CdlValuable, old_value, new_value);
4636 // When appropriate the get_whole_value() call takes care of
4637 // updating the current conflict's solution_references vector. The
4638 // set_whole_value() call updated the per-transaction changes map,
4639 // and also stores sufficient information to support propagation.
4640 // set_whole_value() requires both the old and new values, so
4641 // that propagation can be optimized.
4642 const CdlValue& get_whole_value(CdlConstValuable) const;
4643 void set_whole_value(CdlValuable, const CdlValue&, const CdlValue&);
4645 // Control over active vs. inactive also needs to happen inside
4647 bool is_active(CdlNode) const;
4648 void set_active(CdlNode, bool);
4650 // Callback and parameter settings
4651 static void (*get_callback_fn())(const CdlTransactionCallback&);
4652 static void set_callback_fn(void (*)(const CdlTransactionCallback&));
4653 static void set_inference_callback_fn(CdlInferenceCallback);
4654 static CdlInferenceCallback get_inference_callback_fn();
4655 static void enable_automatic_inference();
4656 static void disable_automatic_inference();
4657 static bool is_automatic_inference_enabled();
4658 static void set_inference_recursion_limit(int);
4659 static int get_inference_recursion_limit();
4660 // The override indicates the highest level of value source that the
4661 // library can overwrite without needing user confirmation. The
4662 // default value is CdlValueSource_Inferred, indicating that the
4663 // library can overwrite default and inferred values but not
4664 // wizard or user values.
4665 static void set_inference_override(CdlValueSource);
4666 static CdlValueSource get_inference_override();
4668 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
4669 CYGDBG_DECLARE_MEMLEAK_COUNTER();
4675 CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
4677 // The associated toplevel and optionally the parent transaction
4678 // and the conflict being worked on
4679 CdlToplevel toplevel;
4680 CdlTransaction parent;
4681 CdlConflict conflict;
4683 // Per-transaction information. All value changes, new conflicts
4684 // etc. first live in the context of a transaction. The global
4685 // configuration only gets updated if the transaction is commited.
4686 // There is also a vector of the pending commit/cancel ops.
4687 std::vector<CdlTransactionCommitCancelOp*> commit_cancel_ops;
4688 std::map<CdlValuable, CdlValue> changes;
4689 std::list<CdlConflict> new_conflicts;
4690 std::list<CdlConflict> new_structural_conflicts;
4691 std::vector<CdlConflict> deleted_conflicts; // Existing global ones
4692 std::vector<CdlConflict> deleted_structural_conflicts;
4693 std::vector<CdlConflict> resolved_conflicts; // New ones already fixed by the inference engine
4694 std::list<CdlConflict> global_conflicts_with_solutions;
4695 std::set<CdlNode> activated;
4696 std::set<CdlNode> deactivated;
4697 std::set<CdlValuable> legal_values_changes;
4700 // Change propagation. It is necessary to keep track of all
4701 // pending value changes, active changes, and of things being
4702 // loaded or unloaded. The set_value() call is used to update the
4703 // value_changes container.
4704 std::deque<CdlValuable> value_changes;
4705 std::deque<CdlNode> active_changes;
4708 // Control over the inference engine etc.
4709 static CdlInferenceCallback inference_callback;
4710 static bool inference_enabled;
4711 static int inference_recursion_limit;
4712 static CdlValueSource inference_override;
4713 static void (*callback_fn)(const CdlTransactionCallback&);
4716 CdlTransactionBody_Invalid = 0,
4717 CdlTransactionBody_Magic = 0x3f91e4df
4718 } cdltransactionbody_cookie;
4720 // Illegal operations
4721 CdlTransactionBody();
4722 CdlTransactionBody(const CdlTransactionBody &);
4723 CdlTransactionBody& operator=(const CdlTransactionBody&);
4727 //{{{ CdlTransactionCallback
4729 // ----------------------------------------------------------------------------
4730 // The callback class is used to inform applications about all the
4731 // changes that are happening, including side effects. Application
4732 // code can install a callback function which gets invoked at the
4733 // end of every transaction.
4735 // NOTE: this implementation is preliminary. In particular it is
4736 // not extensible, it only deals with changes relevant to software
4739 class CdlTransactionCallback {
4741 friend class CdlTest;
4742 friend class CdlTransactionBody;
4745 ~CdlTransactionCallback();
4746 static void (*get_callback_fn())(const CdlTransactionCallback&);
4747 static void set_callback_fn(void (*)(const CdlTransactionCallback&));
4749 // Callback functions should be able to retrieve information
4750 // about the current transaction and toplevel, to avoid the use
4752 CdlTransaction get_transaction() const;
4753 CdlToplevel get_toplevel() const;
4755 // active_changes and legal_values_changes get updated as the
4756 // transaction proceeds, so a set implementation is more
4757 // efficient. The others get filled in during a commit operation.
4758 // A transaction may result in multiple conflicts for a given node
4759 // being eliminated, so again a set is appropriate. For the others
4760 // there is no possibility of duplicates so a vector is better.
4761 std::vector<CdlValuable> value_changes;
4762 std::vector<CdlNode> active_changes;
4763 std::vector<CdlValuable> legal_values_changes;
4764 std::vector<CdlValuable> value_source_changes;
4765 std::vector<CdlConflict> new_conflicts;
4766 std::vector<CdlConflict> new_structural_conflicts;
4767 std::vector<CdlNode> nodes_with_resolved_conflicts;
4768 std::vector<CdlNode> nodes_with_resolved_structural_conflicts;
4770 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
4775 CdlTransactionCallback(CdlTransaction);
4776 CdlTransaction transact;
4778 // Illegal operation.
4779 CdlTransactionCallback();
4782 CdlTransactionCallback_Invalid = 0,
4783 CdlTransactionCallback_Magic = 0x0cec3a95
4784 } cdltransactioncallback_cookie;
4788 //{{{ CdlLocalTransaction
4790 // ----------------------------------------------------------------------------
4791 // A utility class to create a per-function transaction object which gets
4792 // cleaned up automatically should an exception happen.
4794 class CdlLocalTransaction {
4796 friend class CdlTrest;
4799 CdlLocalTransaction(CdlToplevel toplevel) {
4800 transaction = CdlTransactionBody::make(toplevel);
4802 ~CdlLocalTransaction() {
4803 // The destructor may get invoked during exception handling.
4804 // It is assumed that cancelling the transaction would be a
4805 // good thing when that happens. Normal operation should
4806 // go through the body() or commit() members, which clear
4807 // the transaction field.
4808 // There is a slight consistency here. Normally after a
4809 // transaction commit the transaction object is still
4810 // around. Here the transaction object get deleted. This
4811 // is unlikely to matter in practice.
4812 if (0 != transaction) {
4813 transaction->cancel();
4817 CdlTransaction get() {
4821 transaction->body();
4826 transaction->commit();
4831 transaction->propagate();
4834 if (0 != transaction) {
4835 transaction->cancel();
4842 CdlTransaction transaction;
4843 CdlLocalTransaction();
4849 //{{{ Build and define information
4853 // ----------------------------------------------------------------------------
4854 // There are two related concepts: buildable components, and
4855 // definable components. The former typically refers to compiling
4856 // sources files to produce libraries, although other types of build
4857 // are possible. The latter refers to generating header files
4858 // containing the current configuration data. Typically any loadable
4859 // that is buildable is also definable, so that the source files can
4860 // #include the appropriate generated headers and adapt to the
4861 // configuration data that way. The inverse is not true: for example
4862 // in HCDL it may be appropriate to generate a header file but there
4863 // is nothing to be compiled, device drivers are software packages.
4865 // The relevant base classes are as follows:
4867 // 1) CdlBuildable - this object can have build-related properties.
4868 // All buildables are also valuables.
4869 // 2) CdlBuildLoadable - this is a base class for loadables, providing
4870 // some extra properties that are relevant for
4871 // loadables that can involve builds.
4872 // 3) CdlDefinable - this object can result in #define's in a
4873 // header file. All exportables are also
4875 // 4) CdlDefineLoadable - this is a base class for any loadables that
4876 // can contain buildables.
4878 // Support for both buildable and exportable components is part of the
4879 // core library for now. This may change in future, depending on how
4880 // many CDL variants get implemented.
4882 // There are various properties related to building. First, the
4883 // ones applicable to the CdlBuildLoadable class.
4886 // This specifies the default library for anything built in this
4887 // loadable. If there is no library property then it defaults to
4888 // libtarget.a (or rather to a class static that happens to be
4889 // initialized to libtarget.a)
4891 // 2) include_dir <dir>.
4892 // This specifies where the loadable's exported header files should
4893 // end up. The default value is the toplevel, but e.g. the eCos
4894 // kernel specifies an include_dir of cyg/kernel. Note that fixed
4895 // header files are associated with buildables, not definables,
4896 // the latter deal with generated header files only.
4898 // 3) include_files <hdr1 hdr2 ...>
4899 // The recommended directory hierarchy for non-trivial packages
4900 // involves separate subdirectories src, include, cdl, doc, and
4901 // test. This is too heavyweight for very simple packages where it
4902 // is better to keep everything in just one directory. However that
4903 // introduces a potential conflict between public and private
4904 // header files, which can be resolved by the include_files
4905 // property. The actual rules are:
4907 // a) if there an include_files property, that lists all the
4908 // headers that should be exported.
4910 // b) else if there is an include subdirectory, it is assumed that
4911 // all files below that should be exported.
4913 // c) otherwise all files matching a suitable glob pattern should
4914 // be exported. The default pattern is *.h *.hxx *.inl, but can
4917 // 4) makefile <file>
4918 // This allows component developers to provide a GNU makefile to be
4919 // used for building, rather than specify the relevant information
4921 // NOTE: this property is ignored for now. It is roughly
4922 // equivalent to a custom build step where the command is
4923 // "make -C <dir> -f <file>", but in addition it is necessary to
4924 // worry about phony targets for default, clean, etc.
4926 // A DefineLoadable adds the following property:
4928 // 1) define_header <file>
4929 // This specifies the header file that will be generated. If this
4930 // property is absent then the library will generate a default one
4931 // based on the loadable's name, by discarding everything up to and
4932 // including the first underscore, lowercasing the rest, and
4933 // appending .h. For example, CYGPKG_KERNEL would result in a
4934 // header file kernel.h.
4936 // Hardware packages have an implicit "define_header hardware.h"
4939 // A buildable has the following properties:
4941 // 1) compile [-library xyz] <file1> <file2> ...
4942 // This specifies one or more files that need to be compiled.
4943 // By default the resulting object files will go into the
4944 // current library (set via a higher-level library or
4945 // defaulting to libtarget.a).
4947 // Legitimate filename suffixes for compile statements are .c, .cxx
4948 // and .S. Further suffixes may be supported in future. In the
4949 // long term we will need some external data files defining how
4950 // the various suffixes should be handled.
4952 // Associated with every compilation are details of the compiler to
4953 // be used and the compiler flags. For now no attempt is made
4954 // to do anything interesting in this area, although there is
4955 // sufficient information in the database for the needs of
4956 // command line tools.
4958 // Longer term there are complications. Packages may want some
4959 // control over the compiler flags that should be used, e.g.
4960 // "requires {!(flags ~= ".*-fno-rtti.*")}" to guarantee that the
4961 // compiler flags do not include -fno-rtti, rather useful if the
4962 // package's source code depends on that language feature. Mixed
4963 // architecture systems (e.g. ARM/Thumb) will cause problems when
4964 // it comes to selecting the compiler. The exact means by which
4965 // all this will work is not yet clear.
4967 // 2) object [-library xyz] <file1> <file2> ...
4968 // This specifies one or more pre-built object files that should
4969 // go into the appropriate library.
4971 // The problem here is coping with different architectures, and for
4972 // many architectures it will also be necessary to worry about
4973 // multilibs. Third party component vendors are unlikely to supply
4974 // separate object files for every supported architecture and every
4975 // valid multilib within those architectures, so there are
4976 // constraints on the multilib-related compiler flags used for
4977 // building other packages and the application itself.
4979 // NOTE: this property is ignored for now.
4981 // 3) make_object [-library xyz] [-priority pri] <file> <makefile fragment>
4985 // make_object toyslock.o {
4986 // toyslock.o : toyslock.y
4988 // $(CC) $(CFLAGS) -o toyslock.o y.tab.c
4991 // This defines a custom build step for an object file that
4992 // should go into a particular directory. A makefile syntax
4993 // is used to define the rule simply because it is likely
4994 // to be familiar to package developers, and does not
4995 // imply that the builds will happen via a makefile.
4997 // The optional priority field indicates at which stage during
4998 // the build the rule should trigger. The default value is
4999 // 100, which is the same as for all files specified in
5000 // "compile" properties. A lower value means that the object
5001 // will be generated earlier. Libraries are generated at
5002 // priority 200, and "make" properties normally execute at
5004 // NOTE: it is not clear yet whether supporting priorities
5005 // in this way is a good idea, or whether the dependencies
5006 // information could be used instead.
5008 // Unresolved issues:
5010 // a) what commands can be used in the build rules? There
5011 // should be a core set of supported commands, as per
5012 // an eCos toolchain build. It should also be possible
5013 // for packages to provide their own host tools.
5015 // For sourceware folks, moving away from a single toolchain
5016 // tarball and expecting them to download and install
5017 // egcs, binutils and gdb separately is actually a bad
5018 // idea in this regard, it makes it much more likely that
5019 // some users will have an incomplete tools installation and
5020 // hence that builds will fail.
5022 // b) there is an obvious need for variable substitution in the
5023 // rules, e.g. $(CC). At what stage do these variables get
5024 // expanded, and where does the required information live?
5026 // c) who is responsible for header file dependency analysis?
5027 // Should the rules be modified automatically to do this,
5028 // or do we leave this to the package developer? It may be
5029 // very hard to do the former, but the latter will cause
5030 // problems for IDE integration.
5032 // d) in which directory will the rules get run? What prevents
5033 // filename conflicts between different packages?
5035 // NOTE: make_object is not actually required just yet, but the
5036 // issues are much the same as for the "make" property which is
5039 // 4) make [-priority pri] <target> <makefile fragment>
5044 // target.ld : arm.ld
5045 // $(CC) -E -P -xc $(CFLAGS) -o $@ $<
5048 // This defines a custom build step for a target that is not going
5049 // to end up in a library. The main such targets at the moment are
5050 // the linker script, vectors.o, and extras.o, but there may well
5051 // be others in future.
5053 // The default priority for "make" properties is 300, which means
5054 // that the build rules trigger after all normal compilations and
5055 // after the libraries are generated. It is possible to specify
5056 // custom build steps that should run before any compilations
5057 // using a priority < 100.
5059 // Unresolved issues:
5061 // a) what commands can be used?
5063 // b) variable substitution?
5065 // c) header file dependency analysis?
5067 // d) directories and filenames?
5069 // e) where should the resulting files end up? Currently they can
5070 // all go into $(PREFIX)/lib, but in the long term we may
5071 // need to be a bit more flexible.
5073 // 5) build_proc <tcl code>
5075 // This defines some Tcl code that should be run prior to any
5076 // build, for example to generate a source file. It must run
5077 // within the appropriate loadable's Tcl interpreter so that
5078 // it can query the current configuration.
5080 // NOTE: this property is not implemented yet.
5083 // A definable has the following properties:
5086 // Usually the library will generate either one or two #define's
5087 // for every definable, inside the current header file. This can be
5088 // suppressed by the no_define property, which is typically
5089 // accompanied by some other #define-related property such as
5090 // define_proc or define.
5092 // 2) define [-file <filename>] [-format <format_string>] symbol
5093 // This will result in an additional #define for the specified
5094 // symbol in the specified file. The only filenames that are valid
5095 // are the loadable's current filename (as per define_header), and
5096 // the global header file system.h. Use of the latter should be
5099 // The optional format string behaves as per the define_format
5102 // 3) define_format <format_string>
5103 // This is only relevant for booldata or data flavors. By default
5104 // two #define's will be generated (assuming the valuable is active
5107 // #define <symbol> value
5108 // #define <symbol>_value
5110 // The latter will only be generated if the resulting symbol is
5111 // a valid C preprocessor symbol, and is intended to allow the
5112 // use of #ifdef as well as #ifdef (useful if the value is
5115 // The define_format property provides control over the first of
5116 // these two #defines. The net result is that the #define will be
5117 // generated by evaluating the following Tcl fragment:
5119 // set result "#define <symbol> [<format> <value>]"
5121 // Command and variable substitution are available if desired,
5122 // but for anything that complicated the define_proc property
5123 // is normally more useful.
5125 // define_format is only applicable to the default definition,
5126 // so it cannot be used in conjunction with no_define. The
5127 // define property supports a -format option.
5129 // 4) define_proc <tclcode>
5130 // This specifies some Tcl code that should be run when header
5131 // file generation takes place, in addition to any #define's
5132 // generated by default or courtesy of define properties.
5133 // The define_proc property is commonly used in conjunction with
5134 // no_define, but this is not required.
5136 // There will be two channels already set up: cdl_header
5137 // for the current loadable, and cdl_system_header for system.h.
5138 // Writing data to system.h should be avoided.
5140 // 5) if_define <condition> <symbol>
5142 // This property provides direct support for a common programming
5143 // paradigm. It allows direct generation of code like the
5146 // #ifdef CYGSRC_TOYS_BLOCKS
5147 // # define CYGDBG_INFRA_USE_PRECONDITIONS 1
5150 // In this case CYGSRC_TOYS_BLOCKS is the condition and
5151 // CYGDBG_INFRA_USE_PRECONDITIONS is the symbol. The
5152 // #ifdef/#define sequence will be generated in addition to
5153 // any other #define's resulting from the default behaviour,
5154 // the define property, or the define_proc property. It is
5155 // not affected by no_define.
5158 //{{{ The build process
5160 // ----------------------------------------------------------------------------
5161 // For command-line operation the steps involved in doing a build are:
5163 // 1) work out what needs to be built.
5165 // 2) generate a build and install tree. This involves making sure that
5166 // the various directories exist and are accessible.
5168 // 3) generate or update the toplevel makefile.
5170 // 4) generate the configuration header files.
5172 // For operation in an IDE steps (2) and (3) will be handled by
5175 // There is a library call to get hold of all the build information:
5177 // config->get_build_info(CdlBuildInfo &info);
5179 // This erases anything previously present in the build-info argument
5180 // and fills in the information appropriate to the current
5181 // configuration, essentially by walking down the list of loadables
5182 // and each loadable's list of nodes, checking for BuildLoadables
5183 // and Buildables along the way. The BuildInfo class is defined
5186 // An alternative library call can be used to find out about all
5187 // possible files that need to be compiled etc., irrespective of the
5188 // current configuration settings. This could be useful when it
5189 // comes to letting the user control compiler flags etc.
5191 // config->get_all_build_info(CdlBuildInfo& info);
5193 // There is another library call for step (4):
5195 // config->generate_config_headers(std::string directory)
5197 // This will create or update the header files appropriate to
5198 // the current configuration. Temporary files will be generated,
5199 // diff'ed with the current version, and existing files will
5200 // only be modified if necessary. The directory argument
5201 // indicates where the header files should go, i.e. it should
5202 // be the equivalent of $(PREFIX)/include/pkgconf
5204 // This library call does not delete any files it does not
5205 // recognize, that is the responsibility of higher-level code.
5206 // It is possible to get or update a list of the files that
5207 // will be generated:
5209 // config->get_config_headers(std::vector<std::string>& headers)
5211 // The argument will be cleared if necessary and then filled in with
5212 // the current set of header files. Higher level code can compare the
5213 // result with the current files in the directory and take or suggest
5216 // There is also a library call which combines all four stages:
5218 // config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
5221 // The order in which the various build steps happen is important.
5223 // 1) non-configuration headers must be copied from the component
5224 // repository into $(PREFIX)/include. No compiles can happen
5227 // 2) all compile properties can happen in parallel. These have an
5228 // effective priority of 100.
5230 // 3) all make_object priorities can happen in parallel with
5231 // compiles. These have a default priority of 100, but the
5232 // priority can be modified.
5234 // 4) the generated objects and any pre-built objects should be
5235 // incorporated into the appropriate library. This happens
5238 // 5) custom build steps associated with "make" properties should
5239 // now run. These have a default priority of 300, but it is
5240 // possible to override this.
5242 // Usually all source files will come from the component repository,
5243 // which means that they are read-only. Ideally it should also be
5244 // possible for a source file to be copied into the build tree and
5245 // edited there, and subsequent builds should pick up the copy rather
5246 // than the original. The build data generated by libcdl will always
5247 // be in the form of relative pathnames to facilitate this.
5250 //{{{ CdlBuildInfo class
5252 // ----------------------------------------------------------------------------
5253 // Extracting the build information.
5255 // libcdl.a defines the following classes related to build information.
5258 // CdlBuildInfo_Loadable
5259 // CdlBuildInfo_Header
5260 // CdlBuildInfo_Compile
5261 // CdlBuildInfo_Object
5262 // CdlBuildInfo_MakeObject
5263 // CdlBuildInfo_Make
5265 // The build information is organized on a per-loadable basis.
5266 // Higher-level code may choose to flatten this or to keep the
5267 // distinction. A CdlBuildInfo object is primarily a vector of
5268 // CdlBuildInfo_Loadable objects. CdlBuildInfo objects can be created
5271 // In turn, each CdlBuildInfo_Loadable object is primarily a
5272 // collection of five vectors, one each for Header, Compile, Object,
5273 // MakeObject and Make.
5275 // All pathnames in these data structures will use forward slashes as
5276 // the directory separator, irrespective of the host platform. All
5277 // pathnames will be relative.
5279 struct CdlBuildInfo_Header {
5280 std::string source; /* include/cyg_ass.h */
5281 std::string destination; /* cyg/infra/cyg_ass.h */
5284 struct CdlBuildInfo_Compile {
5285 std::string library; /* libtarget.a */
5286 std::string source; /* src/fancy.cxx */
5287 // Compiler and cflags data may be added in future.
5290 struct CdlBuildInfo_Object {
5291 std::string library; /* libtarget.a */
5292 std::string object; /* obj/hello.o */
5295 struct CdlBuildInfo_MakeObject {
5296 cdl_int priority; /* 100 */
5297 std::string library; /* libtarget.a */
5298 std::string object; /* toyslock.o */
5299 std::string deps; /* toyslock.y */
5301 It is not clear whether the deps field is actually useful in the
5302 context of IDE integration, but see the note about arm.inc
5307 A typical value for "rules" might be:
5310 $(CC) $(CFLAGS) -o toyslock.o y.tab.c
5312 Leading white space is not significant. Newlines are significant.
5313 Backslash escapes in the text will not have been processed yet.
5317 struct CdlBuildInfo_Make {
5318 cdl_int priority; /* 300 */
5319 std::string target; /* extras.o */
5320 std::string deps; /* libextras.a */
5325 $(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
5330 class CdlBuildInfo_Loadable {
5332 friend class CdlTest;
5335 std::string name; /* CYGPKG_INFRA */
5336 std::string directory; /* infra/current */
5337 std::vector<CdlBuildInfo_Header> headers;
5338 std::vector<CdlBuildInfo_Compile> compiles;
5339 std::vector<CdlBuildInfo_Object> objects;
5340 std::vector<CdlBuildInfo_MakeObject> make_objects;
5341 std::vector<CdlBuildInfo_Make> makes;
5348 class CdlBuildInfo {
5350 friend class CdlTest;
5354 std::vector<CdlBuildInfo_Loadable> entries;
5362 //{{{ CdlBuildLoadable
5364 // ----------------------------------------------------------------------------
5365 // BuildLoadables are derived from Loadables and are appropriate for
5366 // any loadables that can contain build information. There are a
5367 // number of properties applicable at this level: makefile,
5368 // include_dir, include_files and library. The main interface of
5369 // interest is update_build_info().
5371 // It is likely that all BuildLoadables are also Buildables, but this
5374 class CdlBuildLoadableBody : virtual public CdlLoadableBody
5376 friend class CdlTest;
5379 virtual ~CdlBuildLoadableBody();
5381 // This is the main way to extract information about what should
5382 // get built. It takes into account the active and enabled states,
5384 void update_build_info(CdlBuildInfo&) const;
5386 // An alternative which ignores the active and enabled states.
5387 void update_all_build_info(CdlBuildInfo&) const;
5389 // Property parsers and validation code appropriate for a
5390 // build-loadable object such as makefile
5391 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
5392 void check_properties(CdlInterpreter);
5393 static int parse_library(CdlInterpreter, int, const char*[]);
5394 static int parse_makefile(CdlInterpreter, int, const char*[]);
5395 static int parse_include_dir(CdlInterpreter, int, const char*[]);
5396 static int parse_include_files(CdlInterpreter, int, const char*[]);
5398 // By default any compiled files will go into libtarget.a, which
5399 // is the default value for this variable. Individual applications may
5400 // specify an alternative default library.
5401 static char* default_library_name;
5403 // When filling in a build_info structure the library needs to know
5404 // what constitutes a header file. A glob pattern can be used for this.
5405 // NOTE: in the long term this should come out of a data file.
5406 static char* default_headers_glob_pattern;
5408 virtual std::string get_class_name() const;
5409 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5410 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5413 CdlBuildLoadableBody();
5418 CdlBuildLoadableBody_Invalid = 0,
5419 CdlBuildLoadableBody_Magic = 0x55776643
5420 } cdlbuildloadablebody_cookie;
5422 // Illegal operations
5423 CdlBuildLoadableBody(const CdlBuildLoadableBody&);
5424 CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
5430 // ----------------------------------------------------------------------------
5431 // Buildable objects can have properties such as compile and
5432 // make_object. These properties are not normally accessed
5433 // directly. Instead there is a member function to update a
5434 // CdlBuildInfo_Loadable object.
5436 // The build properties for a given buildable have an effect iff
5437 // that buildable is active, and in addition if the buildable is also
5438 // a valuable then it must be enabled.
5440 class CdlBuildableBody : virtual public CdlNodeBody
5443 friend class CdlTest;
5446 virtual ~CdlBuildableBody();
5448 // This is the main way to extract information about what should
5449 // get built. It takes into account the active and enabled states,
5450 // as appropriate. The second argument indicates the default
5451 // library for the current loadable.
5452 void update_build_info(CdlBuildInfo_Loadable&, std::string) const;
5454 // An alternative which ignores the active and enabled states.
5455 void update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
5457 // Add property parsers and validation code appropriate for a
5458 // buildable object such as compile and make_object
5459 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
5460 void check_properties(CdlInterpreter);
5462 static int parse_build_proc(CdlInterpreter, int, const char*[]);
5463 static int parse_compile(CdlInterpreter, int, const char*[]);
5464 static int parse_make(CdlInterpreter, int, const char*[]);
5465 static int parse_make_object(CdlInterpreter, int, const char*[]);
5466 static int parse_object(CdlInterpreter, int, const char*[]);
5467 static bool split_custom_build_step(std::string /* data */, std::string& /* target */, std::string& /* deps */,
5468 std::string& /* rules*/, std::string& /* error_msg */);
5470 virtual std::string get_class_name() const;
5471 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5472 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5480 CdlBuildableBody_Invalid = 0,
5481 CdlBuildableBody_Magic = 0x16eb1c04
5482 } cdlbuildablebody_cookie;
5484 // Illegal operations
5485 CdlBuildableBody(const CdlBuildableBody&);
5486 CdlBuildableBody& operator=(const CdlBuildableBody&);
5490 //{{{ CdlDefineLoadable
5492 // ----------------------------------------------------------------------------
5493 // DefineLoadables are derived from Loadables and are appropriate for
5494 // any loadables that can result in generated header files containing
5495 // configuration data. There is one applicable property,
5496 // define_header. The main interface of interest is
5497 // generate_config_headers().
5499 class CdlDefineLoadableBody : virtual public CdlLoadableBody
5502 friend class CdlTest;
5505 virtual ~CdlDefineLoadableBody();
5507 // Update the header file for this loadable. The first argument
5508 // is a channel to the loadable-specific header file. The second
5509 // argument is a channel to the global header file.
5510 void generate_config_header(Tcl_Channel, Tcl_Channel) const;
5512 // What header file should be generated for this loadable?
5513 virtual std::string get_config_header() const;
5515 // Add property parsers and validation code.
5516 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
5517 void check_properties(CdlInterpreter);
5518 static int parse_define_header(CdlInterpreter, int, const char*[]);
5520 virtual std::string get_class_name() const;
5521 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5522 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5525 CdlDefineLoadableBody();
5530 CdlDefineLoadableBody_Invalid = 0,
5531 CdlDefineLoadableBody_Magic = 0x7e211709
5532 } cdldefineloadablebody_cookie;
5534 // Illegal operations
5535 CdlDefineLoadableBody(const CdlDefineLoadableBody&);
5536 CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
5542 // ----------------------------------------------------------------------------
5543 // Definables are derived from Valuables and provide support for
5544 // outputting a configuration header file.
5546 class CdlDefinableBody : virtual public CdlValuableBody
5549 friend class CdlTest;
5552 virtual ~CdlDefinableBody();
5554 // Update the header file for this definable. The loadable's Tcl
5555 // interpreter will already have channels cdl_header and
5556 // cdl_system_header set up appropriately.
5557 void generate_config_header( Tcl_Channel, Tcl_Channel) const;
5559 // Add property parsers and validation code.
5560 static void add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers);
5561 void check_properties(CdlInterpreter);
5562 static int parse_define(CdlInterpreter, int, const char*[]);
5563 static int parse_define_format(CdlInterpreter, int, const char*[]);
5564 static int parse_define_proc(CdlInterpreter, int, const char*[]);
5565 static int parse_if_define(CdlInterpreter, int, const char*[]);
5566 static int parse_no_define(CdlInterpreter, int, const char*[]);
5568 virtual std::string get_class_name() const;
5569 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5570 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5578 CdlDefinableBody_Invalid = 0,
5579 CdlDefinableBody_Magic = 0x65a2c95a
5580 } cdldefinablebody_cookie;
5582 // Illegal operations
5583 CdlDefinableBody(const CdlDefinableBody&);
5584 CdlDefinableBody& operator=(const CdlDefinableBody&);
5592 // ----------------------------------------------------------------------------
5593 // A dialog simply inherits from CdlUserVisible and provides convenient
5594 // access to several dialog-specific properties.
5596 class CdlDialogBody :
5597 public virtual CdlUserVisibleBody,
5598 public virtual CdlParentableBody
5600 friend class CdlTest;
5604 virtual ~CdlDialogBody();
5606 // Dialogs may be enabled or disabled globally. This affects
5607 // CdlValuable::get_widget_hint() if the valuable has an associated
5609 static void disable_dialogs();
5610 static void enable_dialogs();
5611 static bool dialogs_are_enabled();
5613 bool has_init_proc() const;
5614 bool has_update_proc() const;
5615 const cdl_tcl_code& get_init_proc() const;
5616 const cdl_tcl_code& get_update_proc() const;
5617 const cdl_tcl_code& get_display_proc() const;
5618 const cdl_tcl_code& get_confirm_proc() const;
5619 const cdl_tcl_code& get_cancel_proc() const;
5621 static int parse_dialog(CdlInterpreter, int, const char*[]);
5622 static int parse_display_proc(CdlInterpreter, int, const char*[]);
5623 static int parse_update_proc(CdlInterpreter, int, const char*[]);
5625 // Persistence support. Dialogs should just be ignored when it
5626 // comes to saving and restoring files.
5627 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
5629 virtual std::string get_class_name() const;
5630 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5631 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5634 // The constructor only gets invoked from inside parse_dialog()
5635 CdlDialogBody(std::string);
5637 static bool dialogs_enabled;
5640 CdlDialogBody_Invalid = 0,
5641 CdlDialogBody_Magic = 0x3f4df391
5642 } cdldialogbody_cookie;
5644 // Illegal operations. The dialog name must be known at the time
5645 // that the object is constructed.
5647 CdlDialogBody(const CdlDialogBody&);
5648 CdlDialogBody& operator=(const CdlDialogBody&);
5654 // ----------------------------------------------------------------------------
5655 // A wizard is very much like a dialog, just a different set of properties.
5657 class CdlWizardBody :
5658 public virtual CdlUserVisibleBody,
5659 public virtual CdlParentableBody
5661 friend class CdlTest;
5665 virtual ~CdlWizardBody();
5667 bool has_init_proc() const;
5668 bool has_decoration_proc() const;
5669 const cdl_tcl_code& get_init_proc() const;
5670 const cdl_tcl_code& get_decoration_proc() const;
5671 const cdl_tcl_code& get_confirm_proc() const;
5672 const cdl_tcl_code& get_cancel_proc() const;
5673 bool has_screen(cdl_int) const;
5674 cdl_int get_first_screen_number() const;
5675 const cdl_tcl_code& get_first_screen() const;
5676 const cdl_tcl_code& get_screen(cdl_int) const;
5677 static int parse_wizard(CdlInterpreter, int, const char*[]);
5678 static int parse_cancel_proc(CdlInterpreter, int, const char*[]);
5679 static int parse_confirm_proc(CdlInterpreter, int, const char*[]);
5680 static int parse_decoration_proc(CdlInterpreter, int, const char*[]);
5681 static int parse_init_proc(CdlInterpreter, int, const char*[]);
5682 static int parse_screen(CdlInterpreter, int, const char*[]);
5684 // Persistence support. Wizards should just be ignored when it
5685 // comes to saving and restoring files.
5686 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
5688 virtual std::string get_class_name() const;
5689 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5690 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5693 // The constructor only gets invoked from inside parse_wizard().
5694 CdlWizardBody(std::string);
5696 // Illegal operations.
5698 CdlWizardBody(const CdlWizardBody&);
5699 CdlWizardBody& operator=(const CdlWizardBody&);
5702 CdlWizardBody_Invalid = 0,
5703 CdlWizardBody_Magic = 0x4ec1c39a
5704 } cdlwizardbody_cookie;
5708 //{{{ CdlInterface class
5710 // ----------------------------------------------------------------------------
5711 // Similarly for interfaces.
5713 class CdlInterfaceBody : public virtual CdlNodeBody,
5714 public virtual CdlUserVisibleBody,
5715 public virtual CdlValuableBody,
5716 public virtual CdlParentableBody,
5717 public virtual CdlBuildableBody,
5718 public virtual CdlDefinableBody
5720 friend class CdlTest;
5724 ~CdlInterfaceBody();
5726 void get_implementers(std::vector<CdlValuable>&) const;
5727 void recalculate(CdlTransaction);
5729 static int parse_interface(CdlInterpreter, int, const char*[]);
5731 // Persistence support. The interface data cannot sensibly be modified
5732 // by users, it is all calculated. However it is useful to have the
5733 // interface data present in the saved file so that users can examine
5734 // dependencies etc.
5735 virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
5736 static void initialize_savefile_support(CdlToplevel);
5737 static int savefile_interface_command(CdlInterpreter, int, const char*[]);
5739 bool was_generated() const;
5740 virtual bool is_modifiable() const;
5741 virtual std::string get_class_name() const;
5742 bool check_this(cyg_assert_class_zeal = cyg_quick) const;
5743 CYGDBG_DECLARE_MEMLEAK_COUNTER();
5746 CdlInterfaceBody(std::string, bool /* generated */);
5750 CdlInterfaceBody_Invalid = 0,
5751 CdlInterfaceBody_Magic = 0x67f7fbe5
5752 } cdlinterfacebody_cookie;
5754 CdlInterfaceBody(const CdlInterfaceBody&);
5755 CdlInterfaceBody& operator=(const CdlInterfaceBody&);
5760 #endif /* !__CDLCORE_HXX */