]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/cdlcore.hxx
RedBoot Release TX53-v3 2012-02-08
[karo-tx-redboot.git] / tools / src / libcdl / cdlcore.hxx
1 #ifndef __CDLCORE_HXX
2 # define __CDLCORE_HXX
3
4 //{{{  Banner
5
6 //==========================================================================
7 //
8 //      cdlcore.hxx
9 //
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.
13 //
14 //==========================================================================
15 //####COPYRIGHTBEGIN####
16 //
17 // ----------------------------------------------------------------------------
18 // Copyright (C) 2002 Bart Veer
19 // Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
20 //
21 // This file is part of the eCos host tools.
22 //
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)
26 // any later version.
27 //
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
31 // more details.
32 //
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.
36 //
37 // ----------------------------------------------------------------------------
38 //
39 //####COPYRIGHTEND####
40 //==========================================================================
41 //#####DESCRIPTIONBEGIN####
42 //
43 // Author(s):           bartv
44 // Contributors:        bartv
45 // Date:                1999-04-15
46 //
47 //####DESCRIPTIONEND####
48 //==========================================================================
49
50 //}}}
51 //{{{  Platform dependencies
52
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.
59 //
60 // Similarly, VC++ gives spurious warnings when it comes to multiple virtual
61 // inheritance.
62 #ifdef _MSC_VER
63 # pragma warning( disable: 4786 )
64 # pragma warning( disable: 4250 )
65 #endif
66
67 //}}}
68 //{{{  nested #include's
69
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.
74 #include <vector>
75 #include <list>
76 #include <map>
77 #include <set>
78 #include <deque>
79 #include <string>
80 #include <functional>
81 #include <algorithm>
82
83 // <cctype> is needed in various places in the implementation.
84 // This #include should be moved to an implementation-specific
85 // header.
86 #include <cctype>
87
88 // Now for some eCos host-side infrastructure headers.
89 //
90 // Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
91 #include <cyg/infra/cyg_type.h>
92
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>
96
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.
101 #ifndef CONST
102 # define __CDL_CONST_UNDEFINED
103 #endif
104 #ifndef EXTERN
105 # define __CDL_EXTERN_UNDEFINED
106 #endif
107 #ifndef VOID
108 # define __CDL_VOID_UNDEFINED
109 #endif
110 #ifndef CHAR
111 # define __CDL_CHAR_UNDEFINED
112 #endif
113 #ifndef SHORT
114 # define __CDL_SHORT_UNDEFINED
115 #endif
116 #ifndef LONG
117 # define __CDL_LONG_UNDEFINED
118 #endif
119
120 extern "C" {
121 #include <tcl.h>
122 }
123
124 #ifdef __CDL_CONST_UNDEFINED
125 # undef CONST
126 # undef __CDL_CONST_UNDEFINED
127 #endif
128 #ifdef __CDL_EXTERN_UNDEFINED
129 # undef EXTERN
130 # undef __CDL_EXTERN_UNDEFINED
131 #endif
132 #ifdef __CDL_VOID_UNDEFINED
133 # undef VOID
134 # undef __CDL_VOID_UNDEFINED
135 #endif
136 #ifdef __CDL_CHAR_UNDEFINED
137 # undef CHAR
138 # undef __CDL_CHAR_UNDEFINED
139 #endif
140 #ifdef __CDL_SHORT_UNDEFINED
141 # undef SHORT
142 # undef __CDL_SHORT_UNDEFINED
143 #endif
144 #ifdef __CDL_LONG_UNDEFINED
145 # undef LONG
146 # undef __CDL_LONG_UNDEFINED
147 #endif
148
149 //}}}
150
151 //{{{  Primitive types, constants:, enums, etc.
152
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.
157 //
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.
164
165 typedef cyg_int64 cdl_int;
166
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.
171
172 typedef std::string  cdl_tcl_code;
173
174 // ----------------------------------------------------------------------------
175 // CDL values.
176 //
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.
182 //
183 //    None  |  Bool
184 //  --------+--------
185 //    Data  |BoolData
186 //
187 //
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.
191 //
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.
198 //
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
203 // range.
204 //
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.
213 //
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.
223 //
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.
233 //
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:
238 //
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).
244 //
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?
250 //
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.
255 //
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.
263 //
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.
271
272 enum CdlValueFlavor {
273     CdlValueFlavor_Invalid      =  0,
274     CdlValueFlavor_None         =  1,
275     CdlValueFlavor_Bool         =  2,
276     CdlValueFlavor_BoolData     =  3,
277     CdlValueFlavor_Data         =  4
278 };
279
280
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.
289 //
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
295 // user's needs.
296 //
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.
301 //
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.
307
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
315 };
316
317 // ----------------------------------------------------------------------------
318 // Update support.
319 //
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.
329 //
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
332 // being unloaded.
333 //
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.
337
338 enum CdlUpdate {
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
347 };
348
349 // ----------------------------------------------------------------------------
350 // Inference engine callback.
351 //
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.
358
359 enum CdlInferenceCallbackResult {
360     CdlInferenceCallbackResult_Continue = 0x01,
361     CdlInferenceCallbackResult_Cancel   = 0x02
362 };
363
364 // ----------------------------------------------------------------------------
365 // Widget hints.
366 //
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.
370
371 enum CdlBoolWidget {
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
377 };
378
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"
398
399     // More to be added, e.g. for compiler flag handling
400 };
401
402 // ----------------------------------------------------------------------------
403 // Value formats.
404 //
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.
411 //
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.
415 enum CdlValueFormat
416 {
417     CdlValueFormat_Default              = 0,
418     CdlValueFormat_Hex                  = 1,
419     CdlValueFormat_Octal                = 2
420 };
421
422 //}}}
423 //{{{  Exception classes
424
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.
430
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.
434
435 class CdlStringException {
436     friend class CdlTest;
437
438   public:
439     CdlStringException(std::string message_arg) {
440         message = message_arg;
441     }
442     CdlStringException(const CdlStringException& original) {
443         message = original.message;
444     }
445     CdlStringException& operator=(const CdlStringException& original) {
446         message = original.message;
447         return *this;
448     }
449     ~CdlStringException() {
450         message = "";
451     }
452     const std::string& get_message() const {
453         return message;
454     }
455   private:
456     std::string message;
457     CdlStringException();
458 };
459
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.
465 //
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.
469
470 class CdlInputOutputException : public CdlStringException {
471     friend class CdlTest;
472   public:
473     CdlInputOutputException(std::string message_arg) :
474         CdlStringException(message_arg) {
475     }
476     CdlInputOutputException(const CdlInputOutputException& original) :
477         CdlStringException(original) {
478     }
479     CdlInputOutputException& operator=(const CdlInputOutputException& original) {
480         (void) CdlStringException::operator=(original);
481         return *this;
482     }
483 };
484
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.
489
490 class CdlParseException : public CdlStringException {
491     friend class CdlTest;
492   public:
493     CdlParseException(std::string message_arg) :
494         CdlStringException(message_arg) {
495     }
496     CdlParseException(const CdlParseException& original) :
497         CdlStringException(original) {
498     }
499     CdlParseException& operator=(const CdlParseException& original) {
500         (void) CdlStringException::operator=(original);
501         return *this;
502     }
503 };
504
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.
508
509 class CdlEvalException : public CdlStringException {
510     friend class CdlTest;
511   public:
512     CdlEvalException(std::string message_arg) :
513         CdlStringException(message_arg) {
514     }
515     CdlEvalException(const CdlEvalException& original) :
516         CdlStringException(original) {
517     }
518     CdlEvalException& operator=(const CdlEvalException& original) {
519         (void) CdlStringException::operator=(original);
520         return *this;
521     }
522 };
523
524 //}}}
525 //{{{  Forward declarations of the body classes
526
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
531 // the core ones.
532
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;
543
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
547 // on the stack.
548 class CdlSimpleValue;
549 class CdlValue;
550 class CdlListValue;
551
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;
564
565 // Base classes. CDL entities such as options and components derive
566 // from one or more of these, using virtual inheritance.
567 //
568 // The lowest-level class is CdlNodeBody.
569 //
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.
574 //
575 // 2) a node has a name that is unique within the hierarchy.
576 //
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.
581 //
582 // 4) nodes can be referred to by properties in other nodes.
583 class CdlNodeBody;
584
585 // A container is a node that can contain other nodes.
586 class CdlContainerBody;
587
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;
593
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;
599
600 // The remaining classes all add functionality to CdlNode, directly or
601 // indirectly.
602 //
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;
607
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;
614
615 // A parentable object has the parent property, i.e. it can
616 // be reparented to anywhere in the hierarchy
617 class CdlParentableBody;
618
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;
623
624 // A loadable that contains buildables
625 class CdlBuildLoadableBody;
626
627 // A definable object is a valuable object whose value can result
628 // in #define statements in a header file
629 class CdlDefinableBody;
630
631 // A loadable which can contain definables
632 class CdlDefineLoadableBody;
633
634 // TODO: add instantiation support
635
636 // Custom dialogs and wizards are provided by the core.
637 class CdlDialogBody;
638 class CdlWizardBody;
639 class CdlInterfaceBody;
640
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;
645
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;
654
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.
666 //
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
675 // complex API.
676 class CdlTransactionBody;
677
678 // This class is used to pass information back to the application
679 // about what has actually changed in a transaction.
680 class CdlTransactionCallback;
681
682
683 // Build info class. This is always an expanded object, but is
684 // needed here to break a circular dependency.
685 class CdlBuildInfo;
686
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.
692
693 typedef CdlExpressionBody*              CdlExpression;
694 typedef CdlListExpressionBody*          CdlListExpression;
695 typedef CdlGoalExpressionBody*          CdlGoalExpression;
696
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;
706
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;
718
719 typedef CdlDialogBody*                  CdlDialog;
720 typedef CdlWizardBody*                  CdlWizard;
721 typedef CdlInterfaceBody*               CdlInterface;
722
723 typedef CdlInterpreterBody*             CdlInterpreter;
724
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;
731
732 typedef CdlTransactionBody*             CdlTransaction;
733
734 // ----------------------------------------------------------------------------
735
736 typedef const CdlExpressionBody*              CdlConstExpression;
737 typedef const CdlListExpressionBody*          CdlConstListExpression;
738 typedef const CdlGoalExpressionBody*          CdlConstGoalExpression;
739
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;
749
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;
761
762 typedef const CdlDialogBody*                  CdlConstDialog;
763 typedef const CdlWizardBody*                  CdlConstWizard;
764 typedef const CdlInterfaceBody*               CdlConstInterface;
765
766 typedef const CdlInterpreterBody*             CdlConstInterpreter;
767
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;
774
775 typedef const CdlTransactionBody*             CdlConstTransaction;
776
777 //}}}
778 //{{{  Miscellaneous types etc.
779
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.
783
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
787 // a package.
788 //
789 // If the error is fatal then this callback function should raise
790 // a CdlParseException.
791 typedef void (*CdlDiagnosticFnPtr)(std::string);
792
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.
799 //
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.
803 //
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
809 //    operations.
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);
813
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);
820
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*[]);
831
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 {
841   public:
842     std::string                 name;
843     CdlInterpreterCommand       command;
844
845     CdlInterpreterCommandEntry() : name(""), command(0) {}
846     CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
847         : name(name_arg), command(command_arg)
848     {
849     }
850     CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
851         : name(name_arg), command(command_arg)
852     {
853     }
854     ~CdlInterpreterCommandEntry()
855     {
856         name = "";
857         command = 0;
858     }
859 };
860
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.
869 //
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.
874 //
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().
881
882 typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
883
884 struct CdlSavefileCommand {
885     std::string           name;
886     CdlSaveCallback       save_callback;
887     CdlInterpreterCommand load_command;
888 };
889
890 // ----------------------------------------------------------------------------
891 // Widget hint.
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;
900 };
901
902 //}}}
903 //{{{  Memory leak detection
904
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.
912 //
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.
919
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
923
924 #ifdef CYGDBG_USE_TRACING
925
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; }
929
930 #else
931
932 #define CYGDBG_MEMLEAK_CONSTRUCTOR()
933 #define CYGDBG_MEMLEAK_DESTRUCTOR()
934 #define CYGDBG_MEMLEAK_CHECKTHIS()
935
936 #endif
937
938 //}}}
939
940 //{{{  Cdl class
941
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.
946
947 class Cdl {
948
949   public:
950
951     static bool         is_valid_value_flavor(CdlValueFlavor);
952     static bool         is_valid_value_source(CdlValueSource);
953
954     static bool         is_valid_cdl_name(const std::string&);
955     static bool         is_valid_c_preprocessor_symbol(const std::string&);
956
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&);
969
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&);
974
975     static std::string  get_library_version();
976     static void         set_interactive(bool = true);
977     static bool         is_interactive();
978
979     static bool         truth() { return true; }
980     static bool         falsehood() { return false; }
981
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);
985
986     // Also provide an STL-friendly comparison class
987     class version_cmp {
988       public:
989         bool operator()(const std::string& v1, const std::string& v2) const {
990             return Cdl::compare_versions(v1,v2) < 0;
991         }
992     };
993
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 */);
997
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&);
1001
1002   private:
1003     static bool         interactive;
1004 };
1005
1006 //}}}
1007 //{{{  CdlInterpreter class
1008
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
1013 // that users see.
1014 //
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.
1026 //
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.
1035 //
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.
1043 //
1044 // The approach taken is as follows:
1045 //
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.
1049 //
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
1053 //    be available.
1054 //
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.
1061
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)
1068 #else
1069 # define CDL_TCL_CONST_CAST(type,var) const_cast<type>(var)
1070 #endif
1071
1072 class CdlInterpreterBody
1073 {
1074     friend class        CdlTest;
1075
1076   public:
1077
1078     CYGDBG_DECLARE_MEMLEAK_COUNTER();
1079
1080     // This is how a top-level (i.e. per-toplevel) interpreter
1081     // should get created.
1082     static CdlInterpreter       make(Tcl_Interp* = 0);
1083
1084     // Create a slave interpreter for reading in the data in e.g. a
1085     // cdl_package
1086     CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
1087
1088     // Make the interpreter safe, a one-way operation.
1089     void                make_safe();
1090
1091     // The destructor is public.
1092     virtual ~CdlInterpreterBody();
1093
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);
1099
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
1103     // the old set.
1104     std::vector<CdlInterpreterCommandEntry>* push_commands(std::vector<CdlInterpreterCommandEntry>&);
1105     void pop_commands(std::vector<CdlInterpreterCommandEntry>*);
1106     std::vector<CdlInterpreterCommandEntry>* get_pushed_commands() const;
1107
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);
1112
1113     // FIXME: add support for variable traces. These are needed
1114     // for cdl_value and similar utilities.
1115
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*);
1122
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&);
1128
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&);
1132
1133     // And support for evaluating an entire file
1134     int eval_file(std::string);
1135     int eval_file(std::string, std::string&);
1136
1137     // For use by commands implemented in C++, a way of setting the result
1138     void set_result(std::string);
1139
1140     // And a utility to get the result as well.
1141     std::string get_result();
1142
1143     // Was the result set by the Tcl interpreter or by libcdl?
1144     bool result_set_by_cdl();
1145
1146     // A utility to quote data that is going to end up in a TCL script.
1147     static std::string quote(std::string);
1148
1149     // Turn some multiline data into a comment.
1150     static std::string multiline_comment(const std::string&, int, int = 0);
1151
1152     // Add some data to a comment, allowing for newlines if necessary
1153     static std::string extend_comment(const std::string&, int, int = 0);
1154
1155     // Write some data to a savefile, throwing an exception on error
1156     void write_data(Tcl_Channel, std::string);
1157
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);
1165
1166     // When parsing a CDL script it is convenient to keep track of
1167     // a number of items:
1168     //
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
1175     //
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()
1179     //
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.
1183     //
1184     // The loadable field is filled in via make_slave()
1185     //
1186     // For some members push and pop functions are more appropriate
1187     // than set.
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);
1208
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.
1213     class DiagSupport {
1214       public:
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);
1219         }
1220         ~DiagSupport() {
1221             interp->pop_error_fn_ptr(saved_error_fn);
1222             interp->pop_warning_fn_ptr(saved_warn_fn);
1223         }
1224     private:
1225         DiagSupport();
1226
1227         CdlInterpreter     interp;
1228         CdlDiagnosticFnPtr saved_error_fn;
1229         CdlDiagnosticFnPtr saved_warn_fn;
1230     };
1231     class ContextSupport {
1232       public:
1233         ContextSupport(CdlInterpreter interp_arg, std::string context) {
1234             interp = interp_arg;
1235             saved_context = interp->push_context(context);
1236         }
1237         ~ContextSupport() {
1238             interp->pop_context(saved_context);
1239         }
1240       private:
1241         ContextSupport();
1242         CdlInterpreter interp;
1243         std::string    saved_context;
1244     };
1245     class ContainerSupport {
1246       public:
1247         ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
1248             interp = interp_arg;
1249             saved_container = interp->push_container(container);
1250         }
1251         ~ContainerSupport() {
1252             interp->pop_container(saved_container);
1253         }
1254       private:
1255         ContainerSupport();
1256         CdlInterpreter interp;
1257         CdlContainer   saved_container;
1258     };
1259     class NodeSupport {
1260       public:
1261         NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
1262             interp = interp_arg;
1263             saved_node = interp->push_node(node);
1264         }
1265         ~NodeSupport() {
1266             interp->pop_node(saved_node);
1267         }
1268       private:
1269         NodeSupport();
1270         CdlInterpreter interp;
1271         CdlNode        saved_node;
1272     };
1273     class CommandSupport {
1274       public:
1275         CommandSupport(CdlInterpreter interp_arg, std::vector<CdlInterpreterCommandEntry>& commands) {
1276             interp = interp_arg;
1277             saved_commands = interp->push_commands(commands);
1278         }
1279         CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
1280             unsigned int i;
1281             for (i = 0; 0 != commands[i].command; i++) {
1282                 new_commands.push_back(commands[i]);
1283             }
1284             interp = interp_arg;
1285             saved_commands = interp->push_commands(new_commands);
1286         }
1287         ~CommandSupport() {
1288             interp->pop_commands(saved_commands);
1289         }
1290
1291       private:
1292         CommandSupport();
1293         CdlInterpreter interp;
1294         std::vector<CdlInterpreterCommandEntry>* saved_commands;
1295         std::vector<CdlInterpreterCommandEntry> new_commands;
1296     };
1297
1298     // Similar utility classes for variables and assoc data.
1299     class VariableSupport {
1300       public:
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);
1305         }
1306         ~VariableSupport() {
1307             interp->unset_variable(varname);
1308         }
1309       private:
1310         VariableSupport();
1311         CdlInterpreter interp;
1312         std::string    varname;
1313     };
1314     class AssocSupport {
1315       public:
1316         AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
1317             interp = interp_arg;
1318             name   = name_arg;
1319             interp->set_assoc_data(name, data, del_proc);
1320         }
1321         ~AssocSupport() {
1322             interp->delete_assoc_data(name);
1323         }
1324       private:
1325         AssocSupport();
1326         CdlInterpreter interp;
1327         const char*    name;
1328     };
1329
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;
1334
1335     // For use by the assertion macros.
1336     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
1337
1338   private:
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*[]);
1342
1343     // This key is used to access the CdlInterpreter assoc data.
1344     static const char*        cdlinterpreter_assoc_data_key;
1345
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*);
1350
1351     // Default constructor, copy constructor and assignment are illegal
1352     CdlInterpreterBody();
1353     CdlInterpreterBody(const CdlInterpreterBody&);
1354     CdlInterpreterBody& operator=(const CdlInterpreterBody&);
1355
1356
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;
1365     CdlNode                     node;
1366     std::string                 context;
1367     CdlDiagnosticFnPtr          error_fn_ptr;
1368     CdlDiagnosticFnPtr          warning_fn_ptr;
1369     bool                        cdl_result;
1370
1371     std::vector<CdlInterpreterCommandEntry>* current_commands; // for push() and pop()
1372
1373     enum {
1374         CdlInterpreterBody_Invalid = 0,
1375         CdlInterpreterBody_Magic   = 0x0be67689
1376     } cdlinterpreterbody_cookie;
1377 };
1378
1379 //}}}
1380 //{{{  CdlReference/Referrer classes
1381
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.
1393 //
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.
1397 //
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
1407 // versa.
1408 //
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.
1413 //
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.
1417 //
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.
1425 //
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.
1431 //
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
1436 // of properties.
1437 //
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.
1441
1442 // ----------------------------------------------------------------------------
1443 // The actual CdlReference class.
1444
1445 class CdlReference {
1446
1447     friend class        CdlTest;
1448
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;
1452
1453   public:
1454
1455     // The default constructor should not normally be used, instead
1456     // a string should be supplied. However there are vectors of
1457     // reference objects...
1458     CdlReference();
1459
1460     // The main constructor supplies the name of the referenced
1461     // entity. The resulting object will be unbound.
1462     CdlReference(const std::string);
1463
1464     // The copy constructor is legal for unbound objects only.
1465     CdlReference(const CdlReference&);
1466
1467     // The assignment operator is needed for STL operations.
1468     // Again it only makes sense of unbound objects.
1469     CdlReference& operator=(const CdlReference&);
1470
1471     // The destructor is only valid for unbound objects. All references
1472     // should be unbound before an entity can be destroyed.
1473     ~CdlReference();
1474
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;
1479
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
1487     // destination.
1488     void bind(CdlNode, CdlProperty, CdlNode);
1489
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);
1494
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();
1498
1499   protected:
1500
1501   private:
1502
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;
1507     CdlNode     dest;
1508
1509     enum {
1510         CdlReference_Invalid = 0,
1511         CdlReference_Magic   = 0x3f908608
1512     } cdlreference_cookie;
1513 };
1514
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.
1521 //
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.
1527 //
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.
1532
1533 class CdlReferrer {
1534
1535     friend class        CdlTest;
1536
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;
1541
1542   public:
1543
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().
1549     CdlReferrer();
1550     CdlReferrer(const CdlReferrer&);
1551     CdlReferrer& operator=(const CdlReferrer&);
1552     ~CdlReferrer();
1553
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();
1559
1560   private:
1561
1562     CdlNode     source;
1563     CdlProperty source_property;
1564
1565     enum {
1566         CdlReferrer_Invalid = 0,
1567         CdlReferrer_Magic   = 0x70e1fc37
1568     } cdlreferrer_cookie;
1569 };
1570
1571 //}}}
1572 //{{{  Value and Expression  classes
1573
1574 //{{{  CdlEvalContext
1575
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.
1581 //
1582 // To avoid passing too many arguments around the various
1583 // evaluation-related routines, a utility class is provided.
1584
1585 class CdlEvalContext {
1586
1587     friend class CdlTest;
1588
1589   public:
1590
1591     CdlTransaction      transaction;
1592     CdlNode             node;
1593     CdlProperty         property;
1594     CdlToplevel         toplevel;
1595
1596     CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
1597     ~CdlEvalContext();
1598
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);
1603
1604     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
1605     CYGDBG_DECLARE_MEMLEAK_COUNTER();
1606
1607   protected:
1608
1609   private:
1610     // Illegal operation, the three fields must always be supplied,
1611     // although they may be zero.
1612     CdlEvalContext();
1613
1614     enum {
1615         CdlEvalContext_Invalid  = 0,
1616         CdlEvalContext_Magic    = 0x03434be9
1617     } cdlevalcontext_cookie;
1618
1619 };
1620
1621 //}}}
1622 //{{{  CdlSimpleValue
1623
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:
1631 //
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.
1636 //
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.
1643 //
1644 //    3) otherwise interpret the value as a string.
1645 //
1646 // The default value is 0.
1647
1648 class CdlSimpleValue {
1649
1650     friend class CdlTest;
1651
1652   public:
1653
1654     CdlSimpleValue();
1655     CdlSimpleValue(std::string);
1656     CdlSimpleValue(cdl_int);
1657     CdlSimpleValue(double);
1658     CdlSimpleValue(const CdlSimpleValue&);
1659     CdlSimpleValue(bool);
1660     ~CdlSimpleValue();
1661
1662     CdlSimpleValue&     operator=(const CdlSimpleValue&);
1663     CdlSimpleValue&     operator=(std::string);
1664     CdlSimpleValue&     operator=(cdl_int);
1665     CdlSimpleValue&     operator=(double);
1666
1667     CdlSimpleValue&     operator=(bool);
1668
1669     bool                operator==(const CdlSimpleValue&) const;
1670     bool                operator!=(const CdlSimpleValue&) const;
1671     bool                operator==(std::string arg) const
1672     {
1673         CdlSimpleValue val(arg);
1674         return *this == val;
1675     }
1676     bool                operator==(cdl_int arg) const
1677     {
1678         CdlSimpleValue val(arg);
1679         return *this == val;
1680     }
1681     bool                operator==(double arg) const
1682     {
1683         CdlSimpleValue val(arg);
1684         return *this == val;
1685     }
1686     bool                operator!=(std::string arg) const
1687     {
1688         CdlSimpleValue val(arg);
1689         return *this != val;
1690     }
1691     bool                operator!=(cdl_int arg) const
1692     {
1693         CdlSimpleValue val(arg);
1694         return *this != val;
1695     }
1696     bool                operator!=(double arg) const
1697     {
1698         CdlSimpleValue val(arg);
1699         return *this != val;
1700     }
1701
1702     void                set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
1703     std::string         get_value() const;
1704
1705     bool                has_integer_value() const;
1706     void                set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
1707     cdl_int             get_integer_value() const;
1708
1709     bool                has_double_value() const;
1710     void                set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
1711     double              get_double_value() const;
1712
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&);
1717
1718     static void         eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
1719
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;
1724
1725     // This class is too simple to warrant even a cookie validation.
1726     bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
1727         return true;
1728     }
1729
1730   protected:
1731
1732   private:
1733     enum {
1734         int_valid       = 0x01,
1735         double_valid    = 0x02,
1736         string_valid    = 0x04,
1737         int_invalid     = 0x08,
1738         double_invalid  = 0x10
1739     };
1740     mutable int         valid_flags;
1741     mutable std::string value;
1742     mutable cdl_int     int_value;
1743     mutable double      double_value;
1744     CdlValueFormat      format;
1745 };
1746
1747 //}}}
1748 //{{{  CdlListValue
1749
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.
1758 //
1759 // A list value contains five sets of data:
1760 //
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
1766 //
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.
1770
1771 class CdlListValue {
1772
1773     friend class        CdlTest;
1774
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;
1778
1779   public:
1780
1781     CdlListValue();
1782     ~CdlListValue();
1783     CdlListValue(const CdlListValue&);
1784     CdlListValue& operator=(const CdlListValue&);
1785
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;
1790
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;
1796
1797     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
1798     CYGDBG_DECLARE_MEMLEAK_COUNTER();
1799
1800   private:
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;
1804
1805     enum {
1806         CdlListValue_Invalid  = 0,
1807         CdlListValue_Magic    = 0x2183a943
1808     } cdllistvalue_cookie;
1809 };
1810
1811 //}}}
1812 //{{{  CdlValue
1813
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.
1821 //
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.
1826 //
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.
1830 //
1831 //     CdlValueFlavor CdlValue::get_flavor() const;
1832 //
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.
1836 //
1837 //     bool CdlValue::is_enabled(...) const;
1838 //
1839 // (The optional argument to is_enabled() is discussed later).
1840 //
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.
1844 //
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;
1850 //
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:
1854 //
1855 //     CdlSimpleValue CdlValue::get_simple_value(...) const;
1856 //
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
1860 // undefined.
1861 //
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
1872 // source.
1873 //
1874 //    CdlValueSource CdlValue::get_source() const;
1875 //
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
1879 // sources.
1880 //
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.
1884 //
1885 //   bool CdlValue::has_source(CdlValueSource) const;
1886 //
1887 //
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:
1891 //
1892 //   void CdlValue::set_flavor(CdlValueFlavor);
1893 //
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.
1897 //
1898 // There are two member functions to manipulate the value source:
1899 //
1900 //     void CdlValue::set_source(CdlValueSource);
1901 //     void CdlValue::invalidate_source(CdlValueSource);
1902 //
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.
1907 //
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.
1912 //
1913 // For values with flavor Bool and BoolData, there are three
1914 // member functions that can be used to control the enabled
1915 // status:
1916 //
1917 //   void CdlValue::set_enabled(bool, CdlValueSource);
1918 //   void CdlValue::enable(CdlValueSource);
1919 //   void CdlValue::disable(CdlValueSource);
1920 //
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.
1927 //
1928 // For values with flavor BoolData and Data the following
1929 // member functions are available to change the value string:
1930 //
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);
1935 //
1936 // For values with flavor BoolData is is possible to
1937 // combine updating the enabled flag and the string value:
1938 //
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);
1951 //
1952 // Obviously many of these functions are just simple inlines.
1953 //
1954 // There is one final member function:
1955 //
1956 //   void CdlValue::set(CdlSimpleValue, CdlValueSource);
1957 //
1958 // This member function is defined to do the right thing,
1959 // whatever the flavor happens to be.
1960
1961 class CdlValue {
1962
1963     friend class CdlTest;
1964
1965   public:
1966
1967     CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
1968     virtual ~CdlValue();
1969     CdlValue(const CdlValue&);
1970     CdlValue&           operator=(const CdlValue&);
1971
1972     CdlValueFlavor      get_flavor() const;
1973     CdlValueSource      get_source() const;
1974     bool                has_source(CdlValueSource) const;
1975
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;
1983
1984     void set_source(CdlValueSource);
1985     void invalidate_source(CdlValueSource);
1986
1987     void set_enabled(bool, CdlValueSource);
1988     void enable(CdlValueSource source)
1989     {
1990         set_enabled(true, source);
1991     }
1992     void disable(CdlValueSource source)
1993     {
1994         set_enabled(false, source);
1995     }
1996
1997     void set_value(CdlSimpleValue&, CdlValueSource);
1998     void set_value(std::string data, CdlValueSource source)
1999     {
2000         CdlSimpleValue val(data);
2001         set_value(val, source);
2002     }
2003     void set_integer_value(cdl_int data, CdlValueSource source)
2004     {
2005         CdlSimpleValue val(data);
2006         set_value(val, source);
2007     }
2008     void set_double_value(double data, CdlValueSource source)
2009     {
2010         CdlSimpleValue val(data);
2011         set_value(val, source);
2012     }
2013     void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
2014     void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
2015     {
2016         CdlSimpleValue val(data);
2017         set_enabled_and_value(enabled, val, source);
2018     }
2019     void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
2020     {
2021         CdlSimpleValue val(data);
2022         set_enabled_and_value(enabled, val, source);
2023     }
2024     void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
2025     {
2026         CdlSimpleValue val(data);
2027         set_enabled_and_value(enabled, val, source);
2028     }
2029     void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2030     {
2031         set_enabled_and_value(true, val, source);
2032     }
2033     void enable_and_set_value(std::string data, CdlValueSource source)
2034     {
2035         set_enabled_and_value(true, data, source);
2036     }
2037     void enable_and_set_value(cdl_int data, CdlValueSource source)
2038     {
2039         set_enabled_and_value(true, data, source);
2040     }
2041     void enable_and_set_value(double data, CdlValueSource source)
2042     {
2043         set_enabled_and_value(true, data, source);
2044     }
2045     void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2046     {
2047         set_enabled_and_value(false, val, source);
2048     }
2049     void disable_and_set_value(std::string data, CdlValueSource source)
2050     {
2051         set_enabled_and_value(false, data, source);
2052     }
2053     void disable_and_set_value(cdl_int data, CdlValueSource source)
2054     {
2055         set_enabled_and_value(false, data, source);
2056     }
2057     void disable_and_set_value(double data, CdlValueSource source)
2058     {
2059         set_enabled_and_value(false, data, source);
2060     }
2061
2062     void set(CdlSimpleValue&, CdlValueSource);
2063
2064     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2065     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2066
2067     // This should only be used by the library itself.
2068     void                set_flavor(CdlValueFlavor);
2069
2070   protected:
2071
2072   private:
2073
2074     CdlValueFlavor      flavor;
2075     CdlValueSource      current_source;
2076
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];
2082     bool                enabled[4];
2083     CdlSimpleValue      values[4];
2084
2085     enum {
2086         CdlValue_Invalid = 0,
2087         CdlValue_Magic   = 0x41837960
2088     } cdlvalue_cookie;
2089 };
2090
2091 //}}}
2092 //{{{  CdlSubexpression
2093
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.
2101 //
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.
2109 //
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.
2115
2116 enum CdlExprOp {
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
2156 };
2157
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.
2164
2165 #define CdlFunction_MaxArgs     3
2166 struct CdlSubexpression {
2167
2168     CdlExprOp           op;
2169     CdlSimpleValue      constants;              // String, integer or double constant
2170     int                 reference_index;        // iff CdlExprOp_Reference
2171
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.
2175
2176     int                 func;                   // iff CdlExprOp_Function
2177     int                 args[CdlFunction_MaxArgs];
2178 };
2179
2180 //}}}
2181 //{{{  CdlFunction
2182
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.
2187
2188 class CdlFunction {
2189
2190     friend class CdlTest;
2191
2192   public:
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)
2198                 );
2199     ~CdlFunction();
2200
2201     static bool         is_function(std::string, int&);
2202     static std::string  get_name(int);
2203     static int          get_args_count(int);
2204
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);
2209
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);
2213
2214   protected:
2215
2216   private:
2217     // Keep track of all functions in the system
2218     static std::vector<CdlFunction*>    all_functions;
2219
2220     // Each function object is given a unique id during initialization
2221     static int          next_id;
2222     int                 id;
2223
2224     // Provided by the constructor
2225     const char*         name;
2226     int                 number_args;
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);
2231
2232     // The default constructor is illegal
2233     CdlFunction();
2234 };
2235
2236 //}}}
2237 //{{{  CdlExpression
2238
2239 // ----------------------------------------------------------------------------
2240 // And now for the expression class itself.
2241
2242 class CdlExpressionBody {
2243
2244     friend class CdlTest;
2245
2246   public:
2247
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();
2256
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.
2263     //
2264     // All of this data is public and can be readily inspected by the
2265     // inference engine, by conflict detection code, by diagnostic
2266     // code, etc.
2267     std::vector<CdlSubexpression>       sub_expressions;
2268     int                                 first_subexpression;
2269     std::vector<CdlReference>           references;
2270     bool                                update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2271
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);
2280
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&);
2289
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
2295     // expression.
2296     //
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&);
2300
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.
2307     //
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&);
2314
2315     // The full original expression is useful for diagnostics purposes
2316     std::string get_original_string() const;
2317
2318     bool        check_this(cyg_assert_class_zeal cyg_quick) const;
2319     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2320
2321   protected:
2322
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();
2327
2328     // The copy constructor has to be usable by derived classes,
2329     // e.g. CdlExpressionProperty
2330     CdlExpressionBody(const CdlExpressionBody&);
2331
2332   private:
2333
2334
2335     // The assignment operator is illegal.
2336     CdlExpressionBody&  operator=(const CdlExpressionBody&);
2337
2338     // The string that was parsed originally
2339     std::string                 expression_string;
2340
2341     enum {
2342         CdlExpressionBody_Invalid       = 0,
2343         CdlExpressionBody_Magic         = 0x760293a3
2344     } cdlexpressionbody_cookie;
2345 };
2346
2347 //}}}
2348 //{{{  CdlListExpression
2349
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.
2354
2355 class CdlListExpressionBody {
2356
2357     friend class CdlTest;
2358
2359   public:
2360
2361     // Availability of constructors etc. is as per the ordinary
2362     // expression class.
2363     virtual ~CdlListExpressionBody();
2364
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;
2371
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);
2375
2376     // Evaluation support. A list expression evaluates to a list value.
2377     void eval(CdlEvalContext&, CdlListValue&);
2378
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);
2386
2387     // The full original expression is useful for diagnostics purposes
2388     std::string get_original_string() const;
2389
2390     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2391     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2392
2393   protected:
2394     CdlListExpressionBody(const CdlListExpressionBody&);
2395     bool        update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2396
2397   private:
2398
2399     CdlListExpressionBody();
2400     CdlListExpressionBody& operator=(const CdlListExpressionBody&);
2401
2402     void eval_internal(CdlEvalContext&, CdlListValue&);
2403     std::string         expression_string;
2404
2405     enum {
2406         CdlListExpressionBody_Invalid   = 0,
2407         CdlListExpressionBody_Magic     = 0x7da4bcc2
2408     } cdllistexpressionbody_cookie;
2409 };
2410
2411 //}}}
2412 //{{{  CdlGoalExpression
2413
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.
2420
2421 class CdlGoalExpressionBody : private CdlExpressionBody {
2422
2423     friend class CdlTest;
2424
2425     typedef CdlExpressionBody inherited;
2426
2427   public:
2428     virtual ~CdlGoalExpressionBody();
2429
2430     static CdlGoalExpression parse(std::string);
2431
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&);
2437
2438     // Provide public access to the underlying expression object,
2439     // useful for the inference engine
2440     CdlExpression               get_expression();
2441
2442     // The full original expression is useful for diagnostics purposes
2443     std::string get_original_string() const;
2444
2445     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2446     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2447
2448   protected:
2449     CdlGoalExpressionBody(const CdlGoalExpressionBody&);
2450
2451
2452   private:
2453
2454     CdlGoalExpressionBody();
2455     CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
2456     void eval_internal(CdlEvalContext&, bool&);
2457
2458     std::string expression_string;
2459
2460     enum {
2461         CdlGoalExpressionBody_Invalid = 0,
2462         CdlGoalExpressionBody_Magic   = 0x5a58bb24
2463     } cdlgoalexpressionbody_cookie;
2464 };
2465
2466 //}}}
2467 //{{{  CdlInfer
2468
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.
2473
2474 class CdlInfer {
2475   public:
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 */);
2482
2483   private:
2484     CdlInfer();
2485 };
2486
2487 //}}}
2488
2489 //}}}
2490 //{{{  CdlConflict classes
2491
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
2499 // conflict.
2500 //
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().
2507 //
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.
2515 //
2516 //
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.
2525 //
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.
2532 //
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.
2536 //
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.
2540 //
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.
2545
2546 class CdlConflictBody {
2547
2548     friend class CdlTest;
2549
2550     // Transactions and conflicts are closely connected
2551     friend class CdlTransactionBody;
2552
2553   public:
2554
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.
2559
2560     // Is this conflict part of a transaction, or has it been committed to the toplevel.
2561     CdlTransaction      get_transaction() const;
2562
2563     // Is inference implemented for this type of conflict?
2564     virtual bool        resolution_implemented() const;
2565
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.
2573     void                resolve();
2574
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.
2579     //
2580     //    A current solution is indicated by a non-empty solution vector.
2581     //
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.
2585     //
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();
2593
2594     // Provide a text message "explaining" the conflict.
2595     // This only makes sense for derived classes.
2596     virtual std::string get_explanation() const = 0;
2597
2598     // Basic information access.
2599     CdlNode             get_node() const;
2600     CdlProperty         get_property() const;
2601     bool                is_structural() const;
2602
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);
2610     void                enable();
2611     bool                is_enabled() const;
2612     std::string         get_disabled_reason() const;
2613
2614     bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
2615     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2616
2617   protected:
2618     CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
2619
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();
2623
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()
2627     CdlNode             node;
2628     CdlProperty         property;
2629
2630   private:
2631
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);
2637
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;
2641
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.
2646     bool                structural;
2647
2648     // Solution support
2649     bool                                           no_solution;
2650     std::vector<std::pair<CdlValuable, CdlValue> > solution;
2651     std::set<CdlValuable>                          solution_references;
2652     void update_solution_validity(CdlValuable);
2653
2654     // Users may disable a conflict. Usually they will have to
2655     // supply a reason for this.
2656     bool                enabled;
2657     std::string         reason;
2658
2659     enum {
2660         CdlConflictBody_Invalid = 0,
2661         CdlConflictBody_Magic   = 0x073e8853
2662     } cdlconflictbody_cookie;
2663
2664     // Illegal operations. Conflicts always live on the heap.
2665     CdlConflictBody();
2666     CdlConflictBody(const CdlConflictBody&);
2667     CdlConflictBody& operator=(const CdlConflictBody&);
2668 };
2669
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
2674 // entity.
2675
2676 class CdlConflict_UnresolvedBody : public CdlConflictBody {
2677
2678     friend class CdlTest;
2679   public:
2680
2681     static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2682
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();
2688
2689   protected:
2690
2691   private:
2692     virtual ~CdlConflict_UnresolvedBody();
2693     CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2694     std::string         target_name;
2695     enum {
2696         CdlConflict_UnresolvedBody_Invalid      = 0,
2697         CdlConflict_UnresolvedBody_Magic        = 0x1b24bb8a
2698     } cdlconflict_unresolvedbody_cookie;
2699
2700     CdlConflict_UnresolvedBody();
2701     CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
2702     CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
2703 };
2704
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
2709 // illegal.
2710
2711 class CdlConflict_IllegalValueBody : public CdlConflictBody {
2712
2713     friend class CdlTest;
2714
2715   public:
2716
2717     static void         make(CdlTransaction, CdlNode, CdlProperty);
2718
2719     bool                resolution_implemented() const;
2720
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();
2726
2727   protected:
2728
2729   private:
2730     virtual ~CdlConflict_IllegalValueBody();
2731     bool    inner_resolve(CdlTransaction, int);
2732     CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
2733     std::string explanation;
2734     enum {
2735         CdlConflict_IllegalValueBody_Invalid    = 0,
2736         CdlConflict_IllegalValueBody_Magic      = 0x4fb27ed1
2737     } cdlconflict_illegalvaluebody_cookie;
2738
2739     CdlConflict_IllegalValueBody();
2740     CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
2741     CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
2742 };
2743
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.
2747
2748 class CdlConflict_EvalExceptionBody : public CdlConflictBody {
2749
2750     friend class CdlTest;
2751
2752   public:
2753
2754     static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2755
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();
2761
2762   protected:
2763
2764   private:
2765     virtual ~CdlConflict_EvalExceptionBody();
2766     CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2767     std::string explanation;
2768     enum {
2769         CdlConflict_EvalExceptionBody_Invalid   = 0,
2770         CdlConflict_EvalExceptionBody_Magic     = 0x7e64bc41
2771     } cdlconflict_evalexceptionbody_cookie;
2772 };
2773
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.
2778
2779 class CdlConflict_RequiresBody : public CdlConflictBody {
2780
2781     friend class CdlTest;
2782
2783   public:
2784
2785     static void         make(CdlTransaction, CdlNode, CdlProperty);
2786     bool                resolution_implemented() const;
2787
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();
2792
2793   protected:
2794
2795   private:
2796     virtual ~CdlConflict_RequiresBody();
2797     bool     inner_resolve(CdlTransaction, int);
2798     CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
2799     enum {
2800         CdlConflict_RequiresBody_Invalid        = 0,
2801         CdlConflict_RequiresBody_Magic          = 0x78436331
2802     } cdlconflict_requiresbody_cookie;
2803 };
2804
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.
2811
2812 class CdlConflict_DataBody : public CdlConflictBody {
2813
2814     friend class CdlTest;
2815
2816   public:
2817
2818     static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2819
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();
2824
2825   protected:
2826
2827   private:
2828     virtual ~CdlConflict_DataBody();
2829     CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2830     std::string message;
2831     enum {
2832         CdlConflict_DataBody_Invalid    = 0,
2833         CdlConflict_DataBody_Magic      = 0x2cec7ad8
2834     } cdlconflict_databody_cookie;
2835 };
2836
2837 //}}}
2838 //{{{  CdlProperty class and derived classes
2839
2840 //{{{  Description
2841
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. ...
2847 //
2848 // The implementation involves a base class CdlProperty and various
2849 // derived classes such as CdlProperty_StringBody and
2850 // CdlProperty_ExpressionBody.
2851 //
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
2857 // constructor.
2858
2859 //}}}
2860 //{{{  CdlPropertyId_xxx
2861
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
2867 // manageable.
2868 //
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.
2873 //
2874 // A compromise solution is to have #define'd string constants.
2875
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"
2918
2919 //}}}
2920 //{{{  Base class
2921
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.
2926
2927 class CdlPropertyBody {
2928
2929     friend class CdlTest;
2930
2931   public:
2932     // The destructor is public, to avoid possible problems with STL.
2933     virtual ~CdlPropertyBody();
2934
2935     // These routines provide access to the basic data.
2936     std::string get_property_name() const;
2937
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;
2944
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);
2949
2950     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2951     CYGDBG_DECLARE_MEMLEAK_COUNTER();
2952
2953   protected:
2954
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
2958     // "doc").
2959     //
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
2965     // wasting memory.
2966     //
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> >&);
2972
2973   private:
2974     // This string indicates the command used to define this property,
2975     // e.g. "doc" or "define_proc". It is provided to the constructor.
2976     std::string                 name;
2977
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;
2982
2983     std::vector<std::pair<std::string, std::string> >   options;
2984
2985     // The usual set of illegal operations.
2986     CdlPropertyBody();
2987     CdlPropertyBody(const CdlPropertyBody&);
2988     CdlPropertyBody& operator=(const CdlPropertyBody&);
2989
2990     enum {
2991         CdlPropertyBody_Invalid = 0,
2992         CdlPropertyBody_Magic   = 0x60dd58f4
2993     } cdlpropertybody_cookie;
2994 };
2995
2996 //}}}
2997 //{{{  CdlProperty_Minimal
2998
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.
3002
3003 class CdlProperty_MinimalBody : public CdlPropertyBody {
3004
3005     friend class CdlTest;
3006
3007   public:
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();
3012
3013   protected:
3014
3015   private:
3016     typedef CdlPropertyBody     inherited;
3017
3018     CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector<std::pair<std::string,std::string> >&);
3019     enum {
3020         CdlProperty_MinimalBody_Invalid = 0,
3021         CdlProperty_MinimalBody_Magic   = 0x25625b8c
3022     } cdlproperty_minimalbody_cookie;
3023
3024     CdlProperty_MinimalBody();
3025     CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
3026     CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
3027 };
3028
3029 //}}}
3030 //{{{  CdlProperty_String
3031
3032 // ----------------------------------------------------------------------------
3033 // A string property contains a single piece of additional data in the form
3034 // of a string.
3035
3036 class CdlProperty_StringBody : public CdlPropertyBody {
3037
3038     friend class CdlTest;
3039
3040   public:
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();
3044
3045     std::string                 get_string(void) const;
3046     bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
3047     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3048
3049   protected:
3050
3051   private:
3052     typedef CdlPropertyBody     inherited;
3053
3054     CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
3055                            std::vector<std::pair<std::string,std::string> >&);
3056     std::string                 data;
3057     enum {
3058         CdlProperty_StringBody_Invalid = 0,
3059         CdlProperty_StringBody_Magic   = 0x78d1ca94
3060     } cdlproperty_stringbody_cookie;
3061
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&);
3066 };
3067
3068 //}}}
3069 //{{{  CdlProperty_TclCode
3070
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.
3075 //
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.
3079
3080
3081 class CdlProperty_TclCodeBody : public CdlPropertyBody {
3082
3083     friend class CdlTest;
3084
3085   public:
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();
3091
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();
3096
3097   private:
3098     typedef CdlPropertyBody     inherited;
3099
3100     CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
3101                             std::vector<std::pair<std::string,std::string> >&);
3102
3103     cdl_int                     number;
3104     cdl_tcl_code                code;
3105     enum {
3106         CdlProperty_TclCodeBody_Invalid = 0,
3107         CdlProperty_TclCodeBody_Magic   = 0x7b14d4e5
3108     } cdlproperty_tclcodebody_cookie;
3109
3110     CdlProperty_TclCodeBody();
3111     CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
3112     CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
3113
3114 };
3115
3116 //}}}
3117 //{{{  CdlProperty_StringVector
3118
3119 // ----------------------------------------------------------------------------
3120 // This is used for multiple constant strings, as opposed to a list
3121 // expression which requires evaluation. One example is a list
3122 // of aliases.
3123
3124 class CdlProperty_StringVectorBody : public CdlPropertyBody {
3125
3126     friend class CdlTest;
3127
3128   public:
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();
3132
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();
3139
3140   private:
3141     typedef CdlPropertyBody            inherited;
3142
3143     CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector<std::string>&, int, const char*[],
3144                                  std::vector<std::pair<std::string,std::string> >&);
3145
3146     std::vector<std::string>            data;
3147     enum {
3148         CdlProperty_StringVectorBody_Invalid = 0,
3149         CdlProperty_StringVectorBody_Magic   = 0x4ed039f3
3150     } cdlproperty_stringvectorbody_cookie;
3151
3152     CdlProperty_StringVectorBody();
3153     CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
3154     CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
3155 };
3156
3157 //}}}
3158 //{{{  CdlProperty_Reference
3159
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.
3165
3166 class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
3167
3168     friend class CdlTest;
3169
3170   public:
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();
3175
3176     void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3177
3178     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3179     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3180
3181   private:
3182     typedef CdlPropertyBody     inherited_property;
3183     typedef CdlReference        inherited_reference;
3184
3185     CdlUpdateHandler            update_handler;
3186
3187     CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
3188                               std::vector<std::pair<std::string,std::string> >&);
3189     enum {
3190         CdlProperty_ReferenceBody_Invalid = 0,
3191         CdlProperty_ReferenceBody_Magic   = 0x78100339
3192     } cdlproperty_referencebody_cookie;
3193
3194     CdlProperty_ReferenceBody();
3195     CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
3196     CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
3197 };
3198
3199 //}}}
3200 //{{{  CdlProperty_Expression
3201
3202 // ----------------------------------------------------------------------------
3203 // An expression property simply inherits its functionality from the basic
3204 // property class and from the expression class.
3205
3206 class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
3207
3208     friend class CdlTest;
3209
3210   public:
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();
3217
3218   private:
3219     typedef CdlPropertyBody     inherited_property;
3220     typedef CdlExpressionBody   inherited_expression;
3221
3222     CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
3223                                std::vector<std::pair<std::string,std::string> >&);
3224
3225     CdlUpdateHandler update_handler;
3226     enum {
3227         CdlProperty_ExpressionBody_Invalid = 0,
3228         CdlProperty_ExpressionBody_Magic   = 0x05fb4056
3229     } cdlproperty_expressionbody_cookie;
3230
3231     CdlProperty_ExpressionBody();
3232     CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
3233     CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
3234 };
3235
3236 //}}}
3237 //{{{  CdlProperty_ListExpression
3238
3239 // ----------------------------------------------------------------------------
3240 // Similarly a list property simply inherits from property and from
3241 // list expressions.
3242
3243 class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
3244
3245     friend class CdlTest;
3246
3247   public:
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();
3254
3255   private:
3256     typedef CdlPropertyBody         inherited_property;
3257     typedef CdlListExpressionBody   inherited_expression;
3258
3259     CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
3260                                    std::vector<std::pair<std::string,std::string> >&);
3261
3262     CdlUpdateHandler update_handler;
3263     enum {
3264         CdlProperty_ListExpressionBody_Invalid = 0,
3265         CdlProperty_ListExpressionBody_Magic   = 0x6b0136f5
3266     } cdlproperty_listexpressionbody_cookie;
3267
3268     CdlProperty_ListExpressionBody();
3269     CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
3270     CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
3271 };
3272
3273 //}}}
3274 //{{{  CdlProperty_GoalExpression
3275
3276 // ----------------------------------------------------------------------------
3277 // And a goal property inherits from property and from goal expressions.
3278
3279 class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
3280
3281     friend class CdlTest;
3282
3283   public:
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();
3290
3291   private:
3292     typedef CdlPropertyBody         inherited_property;
3293     typedef CdlGoalExpressionBody   inherited_expression;
3294
3295     CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
3296                                    std::vector<std::pair<std::string,std::string> >&);
3297
3298     CdlUpdateHandler update_handler;
3299     enum {
3300         CdlProperty_GoalExpressionBody_Invalid = 0,
3301         CdlProperty_GoalExpressionBody_Magic   = 0x08b2b31e
3302     } cdlproperty_goalexpressionbody_cookie;
3303
3304     CdlProperty_GoalExpressionBody();
3305     CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
3306     CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
3307 };
3308
3309 //}}}
3310
3311 //}}}
3312 //{{{  CdlParse class
3313
3314 // ----------------------------------------------------------------------------
3315 // This is another utility class for collecting together parsing-related
3316 // functions.
3317 //
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.
3322
3323 class CdlParse {
3324
3325   public:
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 */, const 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 */);
3334
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);
3340
3341     static std::string  get_expression_error_location(void);
3342
3343     // Support for Tcl's "unknown" command
3344     static int          unknown_command(CdlInterpreter, int, const char*[]);
3345
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);
3351
3352     // Utility parsing routines
3353     static int  parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
3354                                        const char **, void (*)(CdlInterpreter, CdlProperty_Minimal));
3355     static int  parse_string_property(CdlInterpreter, int, const char*[], std::string,
3356                                       const char **, void (*)(CdlInterpreter, CdlProperty_String));
3357     static int  parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
3358                                        const char **, void (*)(CdlInterpreter, CdlProperty_TclCode));
3359     static int  parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
3360                                             const char **, void (*)(CdlInterpreter, CdlProperty_StringVector),
3361                                             bool /* allow_empty */ = false);
3362     static int  parse_reference_property(CdlInterpreter, int, const char*[], std::string,
3363                                          const char **, void (*)(CdlInterpreter, CdlProperty_Reference),
3364                                          bool /* allow_empty */,
3365                                          CdlUpdateHandler);
3366     static int  parse_expression_property(CdlInterpreter, int, const char*[], std::string,
3367                                           const char **, void (*)(CdlInterpreter, CdlProperty_Expression),
3368                                           CdlUpdateHandler);
3369     static int  parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
3370                                               const char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
3371                                               CdlUpdateHandler);
3372     static int  parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
3373                                               const char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
3374                                               CdlUpdateHandler);
3375 };
3376
3377 //}}}
3378 //{{{  CdlNode
3379
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.
3385 //
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
3388 // conflicts.
3389
3390 class CdlNodeBody {
3391
3392     friend class CdlTest;
3393
3394     // Adding and removing nodes from the hierarchy is done
3395     // by CdlToplevel members.
3396     friend class CdlToplevelBody;
3397
3398     // CdlLoadable must be able to access the destructor
3399     friend class CdlLoadableBody;
3400
3401     // It is intended that CdlProperties will also add and remove themselves
3402     friend class CdlPropertyBody;
3403
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;
3408
3409   public:
3410
3411     // Basic information.
3412     std::string         get_name() const;
3413     CdlContainer        get_parent() const;
3414     CdlLoadable         get_owner() const;
3415     CdlToplevel         get_toplevel() const;
3416
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);
3421
3422     // Is this node active or not? The is_active() call refers
3423     // to the global state, things may be different inside a
3424     // transaction.
3425     bool                is_active() const;
3426     bool                is_active(CdlTransaction transaction);
3427
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);
3434
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;
3443
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;
3450
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;
3454
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);
3461
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.
3466     //
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;
3472
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;
3478
3479     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3480     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3481
3482   protected:
3483
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
3487     // later.
3488     CdlNodeBody(std::string);
3489     // A dummy constructor is needed because of the virtual
3490     // inheritance.
3491     CdlNodeBody();
3492
3493     // Nodes cannot be destroyed directly by application code,
3494     // only by higher-level library functions such as unload_package()
3495     virtual ~CdlNodeBody();
3496
3497     // Updating the name is rarely required, but is useful for savefiles.
3498     void                set_name(std::string);
3499
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
3503     bool                active;
3504
3505   private:
3506
3507     // The basic data. The name is known during construction.
3508     // The other three fields get updated by e.g. CdlToplevel::add_node();
3509     std::string         name;
3510     CdlContainer        parent;
3511     CdlLoadable         owner;
3512     CdlToplevel         toplevel;
3513
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;
3517
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;
3522
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;
3527
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
3534     // savefile.
3535     std::vector<std::string> unsupported_savefile_strings;
3536
3537     enum {
3538         CdlNodeBody_Invalid     = 0,
3539         CdlNodeBody_Magic       = 0x309595b5
3540     } cdlnodebody_cookie;
3541
3542     // Illegal operations
3543     CdlNodeBody(const CdlNodeBody&);
3544     CdlNodeBody& operator=(const CdlNodeBody&);
3545 };
3546
3547 //}}}
3548 //{{{  CdlContainer
3549
3550 // ----------------------------------------------------------------------------
3551 // A container is a node that can contain other nodes.
3552
3553 class CdlContainerBody : virtual public CdlNodeBody {
3554
3555     friend class Cdltest;
3556
3557     // Allow CdlNode::check_this() access to the internals
3558     friend class CdlNodeBody;
3559
3560     // Adding a node to the hierarchy is done by a CdlToplevel member.
3561     // Ditto for removing.
3562     friend class CdlToplevelBody;
3563
3564     // Deleting a container can happen inside CdlToplevel and CdlLoadable
3565     friend class CdlLoadableBody;
3566
3567   public:
3568
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;
3573
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);
3577
3578     // Persistence support.
3579     virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3580
3581     virtual std::string get_class_name() const;
3582     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3583     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3584
3585   protected:
3586
3587     // Containers cannot be destroyed explicitly, only via higher-level
3588     // code such as unload_package();
3589     virtual ~CdlContainerBody();
3590
3591     CdlContainerBody();
3592     // Special constructor needed for internal use.
3593     CdlContainerBody(std::string);
3594
3595     // The CdlToplevel class needs access to its own contents.
3596     std::vector<CdlNode>                contents;
3597
3598   private:
3599     enum {
3600         CdlContainerBody_Invalid        = 0,
3601         CdlContainerBody_Magic          = 0x543c5f1d
3602     } cdlcontainerbody_cookie;
3603
3604     // Illegal operations
3605     CdlContainerBody(const CdlContainerBody&);
3606     CdlContainerBody& operator=(const CdlContainerBody&);
3607 };
3608
3609 //}}}
3610 //{{{  CdlLoadable
3611
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.
3619
3620 class CdlLoadableBody : virtual public CdlContainerBody {
3621
3622     friend class CdlTest;
3623
3624     // Allow CdlNode::check_this() access to the internals
3625     friend class CdlNodeBody;
3626
3627     // Adding nodes to the hierarchy is done by a toplevel member
3628     friend class CdlToplevelBody;
3629
3630   public:
3631     virtual ~CdlLoadableBody();
3632
3633
3634     const std::vector<CdlNode>&         get_owned() const;
3635     bool                                owns(CdlConstNode) const;
3636     CdlInterpreter                      get_interpreter() const;
3637     std::string                         get_directory() const;
3638
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;
3644
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);
3652
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);
3657
3658     virtual std::string get_class_name() const;
3659     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3660     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3661
3662   protected:
3663
3664     CdlLoadableBody(CdlToplevel, std::string /* directory */);
3665
3666     // Needed by derived classes, but not actually used.
3667     CdlLoadableBody();
3668
3669   private:
3670
3671     std::vector<CdlNode> owned;
3672     CdlInterpreter       interp;
3673     std::string          directory;
3674
3675     // Used by add/remove_node_from_toplevel()
3676     int                  remove_node_loadables_position;
3677
3678     enum {
3679         CdlLoadableBody_Invalid = 0,
3680         CdlLoadableBody_Magic   = 0x488d6127
3681     } cdlloadablebody_cookie;
3682
3683     // Invalid operations
3684     CdlLoadableBody(const CdlLoadableBody&);
3685     CdlLoadableBody& operator=(const CdlLoadableBody&);
3686 };
3687
3688 //}}}
3689 //{{{  CdlToplevel
3690
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
3696 // facility.
3697 //
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
3702 // needs a name.
3703
3704 class CdlToplevelBody : virtual public CdlContainerBody {
3705
3706     friend class CdlTest;
3707
3708     // Allow CdlNode::check_this() access to the internals
3709     friend class CdlNodeBody;
3710
3711     // The CdlTransaction class needs direct access to the lists
3712     // of conflicts.
3713     friend class CdlTransactionBody;
3714
3715   public:
3716     virtual ~CdlToplevelBody();
3717
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.
3724     //
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.
3734     //
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.
3739     //
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();
3751
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;
3757
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;
3761
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.
3768     //
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
3775     // harmless.
3776     const std::list<CdlConflict>& get_all_conflicts() const;
3777     const std::list<CdlConflict>& get_all_structural_conflicts() const;
3778
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();
3783
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);
3791
3792     // Each toplevel must have an associated master Tcl interpreter.
3793     CdlInterpreter      get_interpreter() const;
3794
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;
3799
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
3803     // are allowed)
3804     CdlTransaction      get_active_transaction() const;
3805
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 = "");
3813
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);
3821     void                clear_limbo();
3822
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);
3840
3841     virtual std::string get_class_name() const;
3842     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3843     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3844
3845   protected:
3846     CdlToplevelBody(CdlInterpreter, std::string);
3847
3848   private:
3849
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;
3859
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;
3865
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;
3873
3874     // Keep track of the current active transaction for this toplevel (if any)
3875     CdlTransaction      transaction;
3876
3877     enum {
3878         CdlToplevelBody_Invalid = 0,
3879         CdlToplevelBody_Magic   = 0x0834666e
3880     } cdltoplevelbody_cookie;
3881
3882     // Invalid operations
3883     CdlToplevelBody(const CdlToplevelBody&);
3884     CdlToplevelBody& operator=(const CdlToplevelBody&);
3885 };
3886
3887 //}}}
3888 //{{{  CdlUserVisible
3889
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.
3895
3896 class CdlUserVisibleBody : virtual public CdlNodeBody {
3897
3898     friend class CdlTest;
3899
3900   public:
3901     virtual ~CdlUserVisibleBody();
3902
3903     std::string         get_display() const;
3904     std::string         get_description() const;
3905     std::string         get_doc() const;
3906
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;
3910
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*[]);
3918
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);
3922
3923     virtual std::string get_class_name() const;
3924     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3925     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3926
3927   protected:
3928     CdlUserVisibleBody();
3929
3930   private:
3931
3932     enum {
3933         CdlUserVisibleBody_Invalid      = 0,
3934         CdlUserVisibleBody_Magic        = 0x13bbc817
3935     } cdluservisiblebody_cookie;
3936
3937     // Illegal operations
3938     CdlUserVisibleBody(const CdlUserVisibleBody&);
3939     CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
3940 };
3941
3942 //}}}
3943 //{{{  CdlParentable
3944
3945 // ----------------------------------------------------------------------------
3946 // A parentable object may have the parent property, redefining its
3947 // position in the hierarchy.
3948
3949 class CdlParentableBody : virtual public CdlNodeBody {
3950
3951     friend class CdlTest;
3952
3953   public:
3954     virtual ~CdlParentableBody();
3955
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);
3960
3961     virtual std::string get_class_name() const;
3962     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3963     CYGDBG_DECLARE_MEMLEAK_COUNTER();
3964
3965   protected:
3966     CdlParentableBody();
3967
3968   private:
3969
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;
3973
3974     enum {
3975         CdlParentableBody_Invalid      = 0,
3976         CdlParentableBody_Magic        = 0x40c6a077
3977     } cdlparentablebody_cookie;
3978
3979     // Illegal operations
3980     CdlParentableBody(const CdlParentableBody&);
3981     CdlParentableBody& operator=(const CdlParentableBody&);
3982 };
3983
3984 //}}}
3985 //{{{  CdlValuable
3986
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.
3992 //
3993 // Relevant properties for a valuable object are:
3994 //
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
4005 //
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
4009 // a CdlValue.
4010
4011 class CdlValuableBody : virtual public CdlNodeBody {
4012
4013     friend class CdlTest;
4014
4015     // Transaction commit operations require direct access to the CdlValue
4016     friend class CdlTransactionBody;
4017
4018   private:
4019     CdlValue value;
4020
4021   public:
4022     virtual ~CdlValuableBody();
4023
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;
4027
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();
4032     }
4033
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;
4043
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;
4053
4054     // -----------------------------------------------------------------
4055     // Modify access. There are two variants of all the functions:
4056     //
4057     // 1) no transaction argument. A transaction will be created,
4058     //    committed, and destroyed for the change in question.
4059     //
4060     // 2) a transaction argument. The existing transaction will be
4061     //    updated but not committed. This allows multiple changes
4062     //    to be grouped together.
4063     //
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);
4072
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&);
4080
4081     void enable(CdlValueSource source)
4082     {
4083         set_enabled(true, source);
4084     }
4085     void disable(CdlValueSource source)
4086     {
4087         set_enabled(false, source);
4088     }
4089     void set_value(std::string data, CdlValueSource source)
4090     {
4091         CdlSimpleValue val(data);
4092         set_value(val, source);
4093     }
4094     void set_integer_value(cdl_int data, CdlValueSource source)
4095     {
4096         CdlSimpleValue val(data);
4097         set_value(val, source);
4098     }
4099     void set_double_value(double data, CdlValueSource source)
4100     {
4101         CdlSimpleValue val(data);
4102         set_value(val, source);
4103     }
4104     void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
4105     {
4106         CdlSimpleValue val(data);
4107         set_enabled_and_value(enabled, val, source);
4108     }
4109     void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
4110     {
4111         CdlSimpleValue val(data);
4112         set_enabled_and_value(enabled, val, source);
4113     }
4114     void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
4115     {
4116         CdlSimpleValue val(data);
4117         set_enabled_and_value(enabled, val, source);
4118     }
4119     void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4120     {
4121         set_enabled_and_value(true, val, source);
4122     }
4123     void enable_and_set_value(std::string data, CdlValueSource source)
4124     {
4125         set_enabled_and_value(true, data, source);
4126     }
4127     void enable_and_set_value(cdl_int data, CdlValueSource source)
4128     {
4129         set_enabled_and_value(true, data, source);
4130     }
4131     void enable_and_set_value(double data, CdlValueSource source)
4132     {
4133         set_enabled_and_value(true, data, source);
4134     }
4135     void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4136     {
4137         set_enabled_and_value(false, val, source);
4138     }
4139     void disable_and_set_value(std::string data, CdlValueSource source)
4140     {
4141         set_enabled_and_value(false, data, source);
4142     }
4143     void disable_and_set_value(cdl_int data, CdlValueSource source)
4144     {
4145         set_enabled_and_value(false, data, source);
4146     }
4147     void disable_and_set_value(double data, CdlValueSource source)
4148     {
4149         set_enabled_and_value(false, data, source);
4150     }
4151     void enable(CdlTransaction transaction, CdlValueSource source)
4152     {
4153         set_enabled(transaction, true, source);
4154     }
4155     void disable(CdlTransaction transaction, CdlValueSource source)
4156     {
4157         set_enabled(transaction, false, source);
4158     }
4159     void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4160     {
4161         CdlSimpleValue val(data);
4162         set_value(transaction, val, source);
4163     }
4164     void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4165     {
4166         CdlSimpleValue val(data);
4167         set_value(transaction, val, source);
4168     }
4169     void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
4170     {
4171         CdlSimpleValue val(data);
4172         set_value(transaction, val, source);
4173     }
4174     void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
4175     {
4176         CdlSimpleValue val(data);
4177         set_enabled_and_value(transaction, enabled, val, source);
4178     }
4179     void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
4180     {
4181         CdlSimpleValue val(data);
4182         set_enabled_and_value(transaction, enabled, val, source);
4183     }
4184     void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
4185     {
4186         CdlSimpleValue val(data);
4187         set_enabled_and_value(transaction, enabled, val, source);
4188     }
4189     void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4190     {
4191         set_enabled_and_value(transaction, true, val, source);
4192     }
4193     void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4194     {
4195         set_enabled_and_value(transaction, true, data, source);
4196     }
4197     void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4198     {
4199         set_enabled_and_value(transaction, true, data, source);
4200     }
4201     void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4202     {
4203         set_enabled_and_value(transaction, true, data, source);
4204     }
4205     void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4206     {
4207         set_enabled_and_value(transaction, false, val, source);
4208     }
4209     void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4210     {
4211         set_enabled_and_value(transaction, false, data, source);
4212     }
4213     void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4214     {
4215         set_enabled_and_value(transaction, false, data, source);
4216     }
4217     void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4218     {
4219         set_enabled_and_value(transaction, false, data, source);
4220     }
4221
4222     // -----------------------------------------------------------------
4223     virtual bool   is_modifiable() const;
4224     void           get_widget_hint(CdlWidgetHint&);
4225
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);
4231
4232     virtual bool test_active(CdlTransaction);
4233
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;
4245
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;
4256
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);
4281
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);
4291
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);
4297
4298     // Similarly check the requires properties
4299     void check_requires(CdlTransaction, CdlProperty_GoalExpression);
4300     void check_requires(CdlTransaction);
4301
4302     // Enabling or disabling a valuable may affect the active state of children
4303     void check_children_active(CdlTransaction);
4304
4305     virtual std::string get_class_name() const;
4306     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
4307     CYGDBG_DECLARE_MEMLEAK_COUNTER();
4308
4309   protected:
4310     CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
4311
4312
4313   private:
4314
4315
4316     enum {
4317         CdlValuableBody_Invalid = 0,
4318         CdlValuableBody_Magic   = 0x2b2acc03
4319     } cdlvaluablebody_cookie;
4320
4321     // Illegal operations
4322     CdlValuableBody(const CdlValuableBody&);
4323     CdlValuableBody& operator=(const CdlValuableBody&);
4324 };
4325
4326 //}}}
4327 //{{{  CdlTransaction etc.
4328
4329 //{{{  Description
4330
4331 // ----------------------------------------------------------------------------
4332 // Transactions. These are used for all changes to a configuration. In some
4333 // cases a transaction is implicit:
4334 //
4335 //    valuable->set_value(...)
4336 //
4337 // The actual implementation of this is:
4338 //
4339 //    valuable->set_value(...)
4340 //        transact = CdlTransactionBody::make(valuable->get_toplevel())
4341 //        valuable->set_value(transact, ...)
4342 //        <complicated bits>
4343 //        transact->commit()
4344 //        delete transact
4345 //
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.
4349 //
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.
4355 //
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
4361 // a transaction.
4362 //
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.
4370 //
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.
4376 //
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.
4380 //
4381 //
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.
4391 //
4392 // Assuming a default setup in a GUI environment, a typical
4393 // sequence of events would be:
4394 //
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()
4402 //                 <inference>
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()
4408 //         delete transact
4409 //
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.
4415 //
4416 //
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.
4422 //
4423 //     <inference>
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
4430 //                 install it
4431 //             else if the solution might e.g. overwrite a user value
4432 //                 keep it, the user can decide during the inference callback
4433 //
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.
4440 //
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.
4445
4446 //}}}
4447 //{{{  CdlTransactionCommitCancelOp
4448
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
4457 // is essential.
4458 //
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.
4463 //
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.
4471 //
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.
4476
4477 class CdlTransactionCommitCancelOp {
4478     friend class CdlTest;
4479
4480   public:
4481
4482     CdlTransactionCommitCancelOp() { }
4483     virtual ~CdlTransactionCommitCancelOp() { };
4484
4485     // The default implementations of both of these do nothing.
4486     // Derived classes should override at least one of these
4487     // functions.
4488     virtual void commit(CdlTransaction transaction) {
4489         CYG_UNUSED_PARAM(CdlTransaction, transaction);
4490     }
4491     virtual void cancel(CdlTransaction transaction) {
4492         CYG_UNUSED_PARAM(CdlTransaction, transaction);
4493     }
4494
4495   protected:
4496
4497   private:
4498 };
4499
4500 //}}}
4501 //{{{  CdlTransaction class
4502
4503 class CdlTransactionBody {
4504
4505     friend class CdlTest;
4506
4507     friend class CdlConflictBody;
4508     friend class CdlValuableBody;
4509
4510   public:
4511
4512     // Create a toplevel transaction
4513     static CdlTransaction make(CdlToplevel);
4514     virtual ~CdlTransactionBody();
4515     CdlToplevel get_toplevel() const;
4516
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;
4522
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.
4529     void        commit();
4530
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();
4537
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;
4541
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;
4546
4547     // A variant which is used for checking the hierarchy when disabling
4548     // a container
4549     bool        subnode_changed_by_user(CdlContainer) const;
4550
4551     // Is one transaction preferable to another?
4552     bool        is_preferable_to(CdlTransaction) const;
4553
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;
4567
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);
4572
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));
4581
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));
4590
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();
4596
4597     // Cancel all the changes done in this transaction. Essentially
4598     // this just involves clearing out all the STL containers.
4599     void        cancel();
4600
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;
4607
4608     // Propagation support
4609     void        add_active_change(CdlNode);
4610     void        add_legal_values_change(CdlValuable);
4611     void        propagate();
4612     bool        is_propagation_required() const;
4613
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);
4618
4619     // An auxiliary function called by the inference engine to perform recursion
4620     bool        resolve_recursion(int);
4621
4622     // This function combines propagation, inference, and commit
4623     // in one easy-to-use package
4624     void        body();
4625
4626     // Changes.
4627     // There is a call to get hold of a CdlValue reference. Modifications
4628     // should happen via a sequence of the form:
4629     //
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);
4635     //
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&);
4644
4645     // Control over active vs. inactive also needs to happen inside
4646     // transactions
4647     bool                is_active(CdlNode) const;
4648     void                set_active(CdlNode, bool);
4649
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();
4667
4668     bool        check_this(cyg_assert_class_zeal = cyg_quick) const;
4669     CYGDBG_DECLARE_MEMLEAK_COUNTER();
4670
4671   protected:
4672
4673   private:
4674
4675     CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
4676
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;
4682
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;
4698     bool                            dirty;
4699
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;
4706
4707
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&);
4714
4715     enum {
4716         CdlTransactionBody_Invalid = 0,
4717         CdlTransactionBody_Magic   = 0x3f91e4df
4718     } cdltransactionbody_cookie;
4719
4720     // Illegal operations
4721     CdlTransactionBody();
4722     CdlTransactionBody(const CdlTransactionBody &);
4723     CdlTransactionBody& operator=(const CdlTransactionBody&);
4724 };
4725
4726 //}}}
4727 //{{{  CdlTransactionCallback
4728
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.
4734 //
4735 // NOTE: this implementation is preliminary. In particular it is
4736 // not extensible, it only deals with changes relevant to software
4737 // configurations.
4738
4739 class CdlTransactionCallback {
4740
4741     friend class CdlTest;
4742     friend class CdlTransactionBody;
4743
4744   public:
4745     ~CdlTransactionCallback();
4746     static void (*get_callback_fn())(const CdlTransactionCallback&);
4747     static void set_callback_fn(void (*)(const CdlTransactionCallback&));
4748
4749     // Callback functions should be able to retrieve information
4750     // about the current transaction and toplevel, to avoid the use
4751     // of statics.
4752     CdlTransaction              get_transaction() const;
4753     CdlToplevel                 get_toplevel() const;
4754
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;
4769
4770     bool check_this(cyg_assert_class_zeal = cyg_quick) const;
4771
4772   protected:
4773
4774   private:
4775     CdlTransactionCallback(CdlTransaction);
4776     CdlTransaction      transact;
4777
4778     // Illegal operation.
4779     CdlTransactionCallback();
4780
4781     enum {
4782         CdlTransactionCallback_Invalid     = 0,
4783         CdlTransactionCallback_Magic       = 0x0cec3a95
4784     } cdltransactioncallback_cookie;
4785 };
4786
4787 //}}}
4788 //{{{  CdlLocalTransaction
4789
4790 // ----------------------------------------------------------------------------
4791 // A utility class to create a per-function transaction object which gets
4792 // cleaned up automatically should an exception happen.
4793
4794 class CdlLocalTransaction {
4795
4796     friend class CdlTrest;
4797
4798   public:
4799     CdlLocalTransaction(CdlToplevel toplevel) {
4800         transaction = CdlTransactionBody::make(toplevel);
4801     }
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();
4814             delete transaction;
4815         }
4816     }
4817     CdlTransaction get() {
4818         return transaction;
4819     }
4820     void body() {
4821         transaction->body();
4822         delete transaction;
4823         transaction = 0;
4824     }
4825     void commit() {
4826         transaction->commit();
4827         delete transaction;
4828         transaction = 0;
4829     }
4830     void propagate() {
4831         transaction->propagate();
4832     }
4833     void destroy() {
4834         if (0 != transaction) {
4835             transaction->cancel();
4836             delete transaction;
4837             transaction = 0;
4838         }
4839     }
4840
4841   private:
4842     CdlTransaction transaction;
4843     CdlLocalTransaction();
4844 };
4845
4846 //}}}
4847
4848 //}}}
4849 //{{{  Build and define information
4850
4851 //{{{  Description
4852
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.
4864 //
4865 // The relevant base classes are as follows:
4866 //
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
4874 //                        valuables.
4875 // 4) CdlDefineLoadable - this is a base class for any loadables that
4876 //                        can contain buildables.
4877 //
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.
4881 //
4882 // There are various properties related to building. First, the
4883 // ones applicable to the CdlBuildLoadable class.
4884 //
4885 // 1) library xyz.
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)
4890 //
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.
4897 //
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:
4906 //
4907 //    a) if there an include_files property, that lists all the
4908 //       headers that should be exported.
4909 //
4910 //    b) else if there is an include subdirectory, it is assumed that
4911 //       all files below that should be exported.
4912 //
4913 //    c) otherwise all files matching a suitable glob pattern should
4914 //       be exported. The default pattern is *.h *.hxx *.inl, but can
4915 //       be overwritten.
4916 //
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
4920 //    via properties.
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.
4925 //
4926 // A DefineLoadable adds the following property:
4927 //
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.
4935 //
4936 //    Hardware packages have an implicit "define_header hardware.h"
4937 //    property.
4938 //
4939 // A buildable has the following properties:
4940 //
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).
4946 //
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.
4951 //
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.
4957 //
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.
4966 //
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.
4970 //
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.
4978 //
4979 //    NOTE: this property is ignored for now.
4980 //
4981 // 3) make_object [-library xyz] [-priority pri] <file> <makefile fragment>
4982 //
4983 //    For example:
4984 //
4985 //    make_object toyslock.o {
4986 //        toyslock.o : toyslock.y
4987 //                yacc toyslock.y
4988 //                $(CC) $(CFLAGS) -o toyslock.o y.tab.c
4989 //    }
4990 //
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.
4996 //
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
5003 //    priority 300.
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.
5007 //
5008 //    Unresolved issues:
5009 //
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.
5014 //
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.
5021 //
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?
5025 //
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.
5031 //
5032 //    d) in which directory will the rules get run? What prevents
5033 //       filename conflicts between different packages?
5034 //
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
5037 //    required.
5038 //
5039 // 4) make [-priority pri] <target> <makefile fragment>
5040 //
5041 //    For example:
5042 //
5043 //    make target.ld {
5044 //    target.ld : arm.ld
5045 //            $(CC) -E -P -xc $(CFLAGS) -o $@ $<
5046 //    }
5047 //
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.
5052 //
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.
5058 //
5059 //    Unresolved issues:
5060 //
5061 //    a) what commands can be used?
5062 //
5063 //    b) variable substitution?
5064 //
5065 //    c) header file dependency analysis?
5066 //
5067 //    d) directories and filenames?
5068 //
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.
5072 //
5073 // 5) build_proc <tcl code>
5074 //
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.
5079 //
5080 //    NOTE: this property is not implemented yet.
5081 //
5082 //
5083 // A definable has the following properties:
5084 //
5085 // 1) no_define
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.
5091 //
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
5097 //    avoided.
5098 //
5099 //    The optional format string behaves as per the define_format
5100 //    property below.
5101 //
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
5105 //    and enabled):
5106 //
5107 //        #define <symbol> value
5108 //        #define <symbol>_value
5109 //
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
5113 //    non-numerical).
5114 //
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:
5118 //
5119 //        set result "#define <symbol> [<format> <value>]"
5120 //
5121 //    Command and variable substitution are available if desired,
5122 //    but for anything that complicated the define_proc property
5123 //    is normally more useful.
5124 //
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.
5128 //
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.
5135 //
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.
5139 //
5140 // 5) if_define <condition> <symbol>
5141
5142 //    This property provides direct support for a common programming
5143 //    paradigm. It allows direct generation of code like the
5144 //    following:
5145 //
5146 //    #ifdef CYGSRC_TOYS_BLOCKS
5147 //    # define CYGDBG_INFRA_USE_PRECONDITIONS 1
5148 //    #endif
5149 //
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.
5156
5157 //}}}
5158 //{{{  The build process
5159
5160 // ----------------------------------------------------------------------------
5161 // For command-line operation the steps involved in doing a build are:
5162 //
5163 // 1) work out what needs to be built.
5164 //
5165 // 2) generate a build and install tree. This involves making sure that
5166 //    the various directories exist and are accessible.
5167 //
5168 // 3) generate or update the toplevel makefile.
5169 //
5170 // 4) generate the configuration header files.
5171 //
5172 // For operation in an IDE steps (2) and (3) will be handled by
5173 // different code.
5174 //
5175 // There is a library call to get hold of all the build information:
5176 //
5177 //     config->get_build_info(CdlBuildInfo &info);
5178 //
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
5184 // further down.
5185 //
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.
5190 //
5191 //    config->get_all_build_info(CdlBuildInfo& info);
5192 //
5193 // There is another library call for step (4):
5194 //
5195 //    config->generate_config_headers(std::string directory)
5196 //
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
5203 //
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:
5208 //
5209 //    config->get_config_headers(std::vector<std::string>& headers)
5210 //
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
5214 // remedial action.
5215 //
5216 // There is also a library call which combines all four stages:
5217 //
5218 //    config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
5219 //
5220 //
5221 // The order in which the various build steps happen is important.
5222 //
5223 // 1) non-configuration headers must be copied from the component
5224 //    repository into $(PREFIX)/include. No compiles can happen
5225 //    before this.
5226 //
5227 // 2) all compile properties can happen in parallel. These have an
5228 //    effective priority of 100.
5229 //
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.
5233 //
5234 // 4) the generated objects and any pre-built objects should be
5235 //    incorporated into the appropriate library. This happens
5236 //    at priority 200.
5237 //
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.
5241 //
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.
5248
5249 //}}}
5250 //{{{  CdlBuildInfo class
5251
5252 // ----------------------------------------------------------------------------
5253 // Extracting the build information.
5254 //
5255 // libcdl.a defines the following classes related to build information.
5256 //
5257 // CdlBuildInfo
5258 // CdlBuildInfo_Loadable
5259 // CdlBuildInfo_Header
5260 // CdlBuildInfo_Compile
5261 // CdlBuildInfo_Object
5262 // CdlBuildInfo_MakeObject
5263 // CdlBuildInfo_Make
5264 //
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
5269 // statically.
5270 //
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.
5274 //
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.
5278
5279 struct CdlBuildInfo_Header {
5280     std::string         source;         /* include/cyg_ass.h    */
5281     std::string         destination;    /* cyg/infra/cyg_ass.h  */
5282 };
5283
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.
5288 };
5289
5290 struct CdlBuildInfo_Object {
5291     std::string         library;        /* libtarget.a          */
5292     std::string         object;         /* obj/hello.o          */
5293 };
5294
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           */
5300     /*
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
5303       above.
5304     */
5305     std::string         rules;
5306     /*
5307       A typical value for "rules" might be:
5308
5309         yacc toyslock.y
5310         $(CC) $(CFLAGS) -o toyslock.o y.tab.c
5311
5312       Leading white space is not significant. Newlines are significant.
5313       Backslash escapes in the text will not have been processed yet.
5314     */
5315 };
5316
5317 struct CdlBuildInfo_Make {
5318     cdl_int             priority;       /* 300                  */
5319     std::string         target;         /* extras.o             */
5320     std::string         deps;           /* libextras.a          */
5321     std::string         rules;
5322     /*
5323       Something like:
5324
5325   $(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
5326
5327     */
5328 };
5329
5330 class CdlBuildInfo_Loadable {
5331
5332     friend class CdlTest;
5333
5334   public:
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;
5342
5343   protected:
5344
5345   private:
5346 };
5347
5348 class CdlBuildInfo {
5349
5350     friend class CdlTest;
5351
5352   public:
5353
5354     std::vector<CdlBuildInfo_Loadable>  entries;
5355
5356   protected:
5357
5358   private:
5359 };
5360
5361 //}}}
5362 //{{{  CdlBuildLoadable
5363
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().
5370 //
5371 // It is likely that all BuildLoadables are also Buildables, but this
5372 // is not required.
5373
5374 class CdlBuildLoadableBody : virtual public CdlLoadableBody
5375 {
5376     friend class CdlTest;
5377
5378   public:
5379     virtual ~CdlBuildLoadableBody();
5380
5381     // This is the main way to extract information about what should
5382     // get built. It takes into account the active and enabled states,
5383     // as appropriate.
5384     void        update_build_info(CdlBuildInfo&) const;
5385
5386     // An alternative which ignores the active and enabled states.
5387     void        update_all_build_info(CdlBuildInfo&) const;
5388
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*[]);
5397
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 const char*        default_library_name;
5402
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 const char*        default_headers_glob_pattern;
5407
5408     virtual std::string get_class_name() const;
5409     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5410     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5411
5412   protected:
5413     CdlBuildLoadableBody();
5414
5415   private:
5416
5417     enum {
5418         CdlBuildLoadableBody_Invalid    = 0,
5419         CdlBuildLoadableBody_Magic      = 0x55776643
5420     } cdlbuildloadablebody_cookie;
5421
5422     // Illegal operations
5423     CdlBuildLoadableBody(const CdlBuildLoadableBody&);
5424     CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
5425 };
5426
5427 //}}}
5428 //{{{  CdlBuildable
5429
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.
5435 //
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.
5439
5440 class CdlBuildableBody : virtual public CdlNodeBody
5441 {
5442
5443     friend class CdlTest;
5444
5445   public:
5446     virtual ~CdlBuildableBody();
5447
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;
5453
5454     // An alternative which ignores the active and enabled states.
5455     void        update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
5456
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);
5461
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 */);
5469
5470     virtual std::string get_class_name() const;
5471     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5472     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5473
5474   protected:
5475     CdlBuildableBody();
5476
5477   private:
5478
5479     enum {
5480         CdlBuildableBody_Invalid        = 0,
5481         CdlBuildableBody_Magic          = 0x16eb1c04
5482     } cdlbuildablebody_cookie;
5483
5484     // Illegal operations
5485     CdlBuildableBody(const CdlBuildableBody&);
5486     CdlBuildableBody& operator=(const CdlBuildableBody&);
5487 };
5488
5489 //}}}
5490 //{{{  CdlDefineLoadable
5491
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().
5498
5499 class CdlDefineLoadableBody : virtual public CdlLoadableBody
5500 {
5501
5502     friend class CdlTest;
5503
5504   public:
5505     virtual ~CdlDefineLoadableBody();
5506
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;
5511
5512     // What header file should be generated for this loadable?
5513     virtual std::string get_config_header() const;
5514
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*[]);
5519
5520     virtual std::string get_class_name() const;
5521     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5522     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5523
5524   protected:
5525     CdlDefineLoadableBody();
5526
5527   private:
5528
5529     enum {
5530         CdlDefineLoadableBody_Invalid   = 0,
5531         CdlDefineLoadableBody_Magic     = 0x7e211709
5532     } cdldefineloadablebody_cookie;
5533
5534     // Illegal operations
5535     CdlDefineLoadableBody(const CdlDefineLoadableBody&);
5536     CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
5537 };
5538
5539 //}}}
5540 //{{{  CdlDefinable
5541
5542 // ----------------------------------------------------------------------------
5543 // Definables are derived from Valuables and provide support for
5544 // outputting a configuration header file.
5545
5546 class CdlDefinableBody : virtual public CdlValuableBody
5547 {
5548
5549     friend class CdlTest;
5550
5551   public:
5552     virtual ~CdlDefinableBody();
5553
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;
5558
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*[]);
5567
5568     virtual std::string get_class_name() const;
5569     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5570     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5571
5572   protected:
5573     CdlDefinableBody();
5574
5575   private:
5576
5577     enum {
5578         CdlDefinableBody_Invalid        = 0,
5579         CdlDefinableBody_Magic          = 0x65a2c95a
5580     } cdldefinablebody_cookie;
5581
5582     // Illegal operations
5583     CdlDefinableBody(const CdlDefinableBody&);
5584     CdlDefinableBody& operator=(const CdlDefinableBody&);
5585 };
5586
5587 //}}}
5588
5589 //}}}
5590 //{{{  CdlDialog
5591
5592 // ----------------------------------------------------------------------------
5593 // A dialog simply inherits from CdlUserVisible and provides convenient
5594 // access to several dialog-specific properties.
5595
5596 class CdlDialogBody :
5597     public virtual CdlUserVisibleBody,
5598     public virtual CdlParentableBody
5599 {
5600     friend class CdlTest;
5601
5602   public:
5603
5604     virtual ~CdlDialogBody();
5605
5606     // Dialogs may be enabled or disabled globally. This affects
5607     // CdlValuable::get_widget_hint() if the valuable has an associated
5608     // custom dialog.
5609     static void         disable_dialogs();
5610     static void         enable_dialogs();
5611     static bool         dialogs_are_enabled();
5612
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;
5620
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*[]);
5624
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);
5628
5629     virtual std::string get_class_name() const;
5630     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5631     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5632
5633   private:
5634     // The constructor only gets invoked from inside parse_dialog()
5635     CdlDialogBody(std::string);
5636
5637     static bool         dialogs_enabled;
5638
5639     enum {
5640         CdlDialogBody_Invalid   = 0,
5641         CdlDialogBody_Magic     = 0x3f4df391
5642     } cdldialogbody_cookie;
5643
5644     // Illegal operations. The dialog name must be known at the time
5645     // that the object is constructed.
5646     CdlDialogBody();
5647     CdlDialogBody(const CdlDialogBody&);
5648     CdlDialogBody& operator=(const CdlDialogBody&);
5649 };
5650
5651 //}}}
5652 //{{{  CdlWizard
5653
5654 // ----------------------------------------------------------------------------
5655 // A wizard is very much like a dialog, just a different set of properties.
5656
5657 class CdlWizardBody :
5658     public virtual CdlUserVisibleBody,
5659     public virtual CdlParentableBody
5660 {
5661     friend class CdlTest;
5662
5663   public:
5664
5665     virtual ~CdlWizardBody();
5666
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*[]);
5683
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);
5687
5688     virtual std::string get_class_name() const;
5689     bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5690     CYGDBG_DECLARE_MEMLEAK_COUNTER();
5691
5692   private:
5693     // The constructor only gets invoked from inside parse_wizard().
5694     CdlWizardBody(std::string);
5695
5696     // Illegal operations.
5697     CdlWizardBody();
5698     CdlWizardBody(const CdlWizardBody&);
5699     CdlWizardBody& operator=(const CdlWizardBody&);
5700
5701     enum {
5702         CdlWizardBody_Invalid   = 0,
5703         CdlWizardBody_Magic     = 0x4ec1c39a
5704     } cdlwizardbody_cookie;
5705 };
5706
5707 //}}}
5708 //{{{  CdlInterface class
5709
5710 // ----------------------------------------------------------------------------
5711 // Similarly for interfaces.
5712
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
5719 {
5720     friend class CdlTest;
5721
5722   public:
5723
5724     ~CdlInterfaceBody();
5725
5726     void                get_implementers(std::vector<CdlValuable>&) const;
5727     void                recalculate(CdlTransaction);
5728
5729     static int          parse_interface(CdlInterpreter, int, const char*[]);
5730
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*[]);
5738
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();
5744
5745   private:
5746     CdlInterfaceBody(std::string, bool /* generated */);
5747     bool        generated;
5748
5749     enum {
5750         CdlInterfaceBody_Invalid   = 0,
5751         CdlInterfaceBody_Magic     = 0x67f7fbe5
5752     } cdlinterfacebody_cookie;
5753     CdlInterfaceBody();
5754     CdlInterfaceBody(const CdlInterfaceBody&);
5755     CdlInterfaceBody& operator=(const CdlInterfaceBody&);
5756 };
5757
5758 //}}}
5759
5760 #endif  /* !__CDLCORE_HXX */
5761 // EOF cdlcore.hxx