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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [libcdl/] [cdlcore.hxx] - Blame information for rev 857

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
#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
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####
16
// -------------------------------------------
17
// This file is part of the eCos host tools.
18
// Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
19
//
20
// This program is free software; you can redistribute it and/or modify
21
// it under the terms of the GNU General Public License as published by
22
// the Free Software Foundation; either version 2 or (at your option) any
23
// later version.
24
//
25
// This program is distributed in the hope that it will be useful, but
26
// WITHOUT ANY WARRANTY; without even the implied warranty of
27
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28
// General Public License for more details.
29
//
30
// You should have received a copy of the GNU General Public License
31
// along with this program; if not, write to the
32
// Free Software Foundation, Inc., 51 Franklin Street,
33
// Fifth Floor, Boston, MA  02110-1301, USA.
34
// -------------------------------------------
35
// ####ECOSHOSTGPLCOPYRIGHTEND####
36
//==========================================================================
37
//#####DESCRIPTIONBEGIN####
38
//
39
// Author(s):           bartv
40
// Contributors:        bartv
41
// Date:                1999-04-15
42
//
43
//####DESCRIPTIONEND####
44
//==========================================================================
45
 
46
//}}}
47
//{{{  Platform dependencies
48
 
49
// ----------------------------------------------------------------------------
50
// Visual C++ has the delightful feature that the source browser will generate
51
// warnings if there are any identifiers of length >= 256 characters, while at
52
// the same time use of templates in the standard C++ library can easily
53
// generate functions that long. It appears that the only way to disable the
54
// warnings is by use of a %$#@(%*&%! #pragma.
55
//
56
// Similarly, VC++ gives spurious warnings when it comes to multiple virtual
57
// inheritance.
58
#ifdef _MSC_VER
59
# pragma warning( disable: 4786 )
60
# pragma warning( disable: 4250 )
61
#endif
62
 
63
//}}}
64
//{{{  nested #include's
65
 
66
// ----------------------------------------------------------------------------
67
// The libcdl API is defined using parts of the standard C++ library,
68
// including strings and various bits of STL. Therefore these headers must
69
// be #include'd here for the header file to work.
70
#include 
71
#include 
72
#include 
73
#include 
74
#include 
75
#include 
76
#include 
77
#include 
78
 
79
//  is needed in various places in the implementation.
80
// This #include should be moved to an implementation-specific
81
// header.
82
#include 
83
 
84
// Now for some eCos host-side infrastructure headers.
85
//
86
// Get the cyg_int64 data type and CYG_UNUSED_PARAM() macro.
87
#include 
88
 
89
// Some of the classes need to reference the cyg_assert_class_zeal enum.
90
// Also inline functions may perform assertions.
91
#include 
92
 
93
// This header file also depends on having a suitable Tcl installation
94
// Unfortunately  does some ugly things in the interests of
95
// portability, including defining symbols such as EXTERN when
96
// necessary, and this has to be patched up here as cleanly as possible.
97
#ifndef CONST
98
# define __CDL_CONST_UNDEFINED
99
#endif
100
#ifndef EXTERN
101
# define __CDL_EXTERN_UNDEFINED
102
#endif
103
#ifndef VOID
104
# define __CDL_VOID_UNDEFINED
105
#endif
106
#ifndef CHAR
107
# define __CDL_CHAR_UNDEFINED
108
#endif
109
#ifndef SHORT
110
# define __CDL_SHORT_UNDEFINED
111
#endif
112
#ifndef LONG
113
# define __CDL_LONG_UNDEFINED
114
#endif
115
 
116
extern "C" {
117
#include 
118
}
119
 
120
#ifdef __CDL_CONST_UNDEFINED
121
# undef CONST
122
# undef __CDL_CONST_UNDEFINED
123
#endif
124
#ifdef __CDL_EXTERN_UNDEFINED
125
# undef EXTERN
126
# undef __CDL_EXTERN_UNDEFINED
127
#endif
128
#ifdef __CDL_VOID_UNDEFINED
129
# undef VOID
130
# undef __CDL_VOID_UNDEFINED
131
#endif
132
#ifdef __CDL_CHAR_UNDEFINED
133
# undef CHAR
134
# undef __CDL_CHAR_UNDEFINED
135
#endif
136
#ifdef __CDL_SHORT_UNDEFINED
137
# undef SHORT
138
# undef __CDL_SHORT_UNDEFINED
139
#endif
140
#ifdef __CDL_LONG_UNDEFINED
141
# undef LONG
142
# undef __CDL_LONG_UNDEFINED
143
#endif
144
 
145
//}}}
146
 
147
//{{{  Primitive types, constants:, enums, etc.
148
 
149
// ----------------------------------------------------------------------------
150
// The CDL languages are defined in terms of arbitrary precision
151
// arithmetic. This is necessary to allow e.g. pointers to be
152
// manipulated at the CDL level on 64 bit target processors.
153
//
154
// Temporarily it is not necessary to provide this precision, so it is
155
// convenient to stick to 64 bit integers as provided by the
156
// underlying infrastructure. However the API is defined in terms of
157
// the type cdl_int, so that it will be easier in future to make the
158
// change to the correct datatype. At that point cdl_int can be
159
// redefined to be a class which supports the appropriate operators.
160
 
161
typedef cyg_int64 cdl_int;
162
 
163
// ---------------------------------------------------------------------------
164
// A common concept in the CDL language is a small amount of TCL code.
165
// This is currently stored as a simple string. Conceivably it could
166
// be byte-compiled and stored accordingly.
167
 
168
typedef std::string  cdl_tcl_code;
169
 
170
// ----------------------------------------------------------------------------
171
// CDL values.
172
//
173
// CDL is a declarative programming language. It does involve the
174
// manipulation of values, but such values do not necessarily
175
// correspond to hardware-level entities such as integers or double
176
// precision numbers. Hence the term "type" is avoided, "flavor"
177
// is used instead. CDL understands four different flavors.
178
//
179
//    None  |  Bool
180
//  --------+--------
181
//    Data  |BoolData
182
//
183
//
184
// The flavor "none" is used for entities that serve only as
185
// placeholders in the hierarchy, allowing other entities to be
186
// grouped more easily.
187
//
188
// Boolean entities can be either enabled or disabled. This is the
189
// most common flavor for software configuration options, the user can
190
// either enable or disable some unit of functionality. For software
191
// packages implemented in C or C++ the implementation is obvious: iff
192
// the entity is enabled then there will be a #define, and code will
193
// check the setting using e.g. #ifdef.
194
//
195
// The flavor "data" implies some arbitrary data. Internally this will
196
// be held as a string. Other properties such as legal_values,
197
// check_proc and entry_proc can be used to constrain the
198
// actual values, for example to an integer value within a certain
199
// range.
200
//
201
// The flavor "booldata" combines the previous two: it means that
202
// the option can be either enabled or disabled, and if it is
203
// enabled then it must have a value as per legal_values etc.
204
// One example of this is a software package: this may be either
205
// enabled or disabled, and if it is enabled then it has a value
206
// corresponding to the version string. Another example is a hardware
207
// pin: this may or may not be connected, and if it is connected
208
// then its value identifies some other pin.
209
//
210
// An entity's flavor is not always sufficient by itself to specify
211
// how the user can manipulate it in a graphical tool. Obviously an
212
// entity of flavor "none" cannot be manipulated at all. Flavor "bool"
213
// normally implies a checkbutton, but occasionally a radiobutton will
214
// be more appropriate. "Data" says very little about the user
215
// interaction, it will be necessary to examine other properties such
216
// as legal_values to determine a sensible representation. The same
217
// goes for "BoolData", with the additional possibility that the
218
// entity may be disabled.
219
//
220
// It can be argued that three of the flavors are redundant: both Bool
221
// and BoolData could be implemented as cases of "Data" with a special
222
// legal value "disabled" (or false, or whatever); "None" could be
223
// implemented as constant "Data"; effectively CDL would manipulate
224
// all data as strings, just like e.g. all variables in Tcl, or just
225
// like all scalars in Perl. This approach is certainly tempting and
226
// might well make it easier to document the language, but in practice
227
// it would result in more verbose CDL: boolean entities really are a
228
// different beast from data entities.
229
//
230
// It can also be argued that there should be more flavors. For
231
// example there could be separate flavors for integer data, floating
232
// point data, string data, and so on. There are a number of good
233
// reasons for not doing so:
234
//
235
// 1) applying separate constraints such as legal_values allows much
236
//    finer control over the actual values, for example numbers within a
237
//    given range. As likely as not, a value will be constrained to
238
//    something smaller than the range MININT to MAXINT (whatever those
239
//    happen to be for the current target).
240
//
241
// 2) where do you stop? Do you provide separate flavors for signed
242
//    vs. unsigned? Char, wchar_t, short, int, long, long long? How about
243
//    the eCos data types cyg_ucount8, cyg_uint8, ... Is there support
244
//    for enums? Arrays? Bitfields? Structures? Unions? C++ classes?
245
//    How about other programming languages such as Ada or Java?
246
//
247
//    Any attempt to implement a grand union of all data types in CDL
248
//    is doomed to failure and should not be attempted. Treating
249
//    everything as a string instead has proven successful in a number
250
//    of languages, including Tcl and Perl.
251
//
252
// 3) for some variants of CDL, for example hardware CDL, it may not
253
//    make much sense to display a value directly and allow it to be
254
//    manipulated directly. The value associated with a pin entity
255
//    identifies the pin to which it is connected, and typically
256
//    this value will be manipulated by drag and drop rather than by
257
//    typing some characters. Such a value certainly does not correspond
258
//    to any machine data type.
259
//
260
// Another reason for extending the number of flavors is to provide
261
// more information. For example there could be a specialized version
262
// of the boolean flavor called "radio". This would imply a specific
263
// representation in the user interface, and it would also impose
264
// a constraint that it implicitly precludes any other radio entities
265
// within the same group. However the same information can be specified
266
// by other more general means such as requires statements.
267
 
268
enum CdlValueFlavor {
269
    CdlValueFlavor_Invalid      =  0,
270
    CdlValueFlavor_None         =  1,
271
    CdlValueFlavor_Bool         =  2,
272
    CdlValueFlavor_BoolData     =  3,
273
    CdlValueFlavor_Data         =  4
274
};
275
 
276
 
277
// Another important aspect of a value is where it came from. There
278
// are a number of possible sources: the default value, calculated
279
// from a default_value property; a value inferred by the inference
280
// engine; a value set by a wizard; and a value set explicitly by
281
// the user. These sources have different priorities, so for example
282
// the inference engine can safely replace a calculated default
283
// value without prompting the user, but changing a user-set value
284
// automatically is undesirable.
285
//
286
// Wizard-generated values are considered more valuable than default
287
// or inferred values (there is some user input involved), but less
288
// valuable than values set explicitly by the user: the idea is that
289
// a wizard asks fairly generic questions and makes a best guess at
290
// the correct values, which may not be precise enough for the
291
// user's needs.
292
//
293
// Arguably dialogs provide a level between wizards and users, in that
294
// a dialog can theoretically manipulate several entities in one go so
295
// it is a less precise way of setting values. At this stage it does
296
// not seem worthwhile to add this distinction.
297
//
298
// The library actually maintains separate values for each source,
299
// as well as the current source which is what actually gets used.
300
// In theory it is possible for the user interface code to let
301
// the user switch between these. It is not yet clear whether this
302
// makes sense from an end user's perspective.
303
 
304
enum CdlValueSource {
305
    CdlValueSource_Invalid              = -1, // 0 is needed for array indexing
306
    CdlValueSource_Default              =  0,
307
    CdlValueSource_Inferred             =  1,
308
    CdlValueSource_Wizard               =  2,
309
    CdlValueSource_User                 =  3,
310
    CdlValueSource_Current              =  4
311
};
312
 
313
// ----------------------------------------------------------------------------
314
// Update support.
315
//
316
// When there is a change to a node and there are references to that node,
317
// the referencing properties will want to be informed about this. There
318
// are various different kinds of changes, not all of which are always
319
// relevant. For example, if a CDL entity gets destroyed or unloaded then
320
// all referencing entities are likely to want to know about this, but
321
// if a container's value changes then this has no effect on a reference
322
// in e.g. a "parent" property. In some cases it is also useful to apply
323
// updates to nodes rather than properties, e.g. when a node becomes
324
// active or inactive.
325
//
326
// The generic update code is also used for initialization and finalization,
327
// i.e. when the source object itself has just been loaded or is
328
// being unloaded.
329
//
330
// For any particular update at most one bit set, but it is often
331
// appropriate to treat several different kinds of update with
332
// common code. Hence the enum values can be or'ed and and'ed.
333
 
334
enum CdlUpdate {
335
    CdlUpdate_Loaded            = 0x0001,       // The source has just been loaded
336
    CdlUpdate_Init              = 0x0002,       // Second-phase of a load operation
337
    CdlUpdate_Unloading         = 0x0004,       // The source is being unloaded
338
    CdlUpdate_Created           = 0x0008,       // The destination has just been created
339
    CdlUpdate_Destroyed         = 0x0010,       // The destination is being destroyed
340
    CdlUpdate_ValueChange       = 0x0020,       // The destination's value has changed.
341
                                                // This gets applied to nodes as well
342
    CdlUpdate_ActiveChange      = 0x0040        // The node has become active or inactive
343
};
344
 
345
// ----------------------------------------------------------------------------
346
// Inference engine callback.
347
//
348
// During a transaction there may be one or more invocations of the inference
349
// engine, followed by a callback which should display the current transaction
350
// status to the user and allow one or more recommended fixes to be accepted.
351
// The callback's return code indicates what should happen next. "Cancel"
352
// is pretty obvious. "Continue" may result in a commit, or it may result in
353
// another iteration.
354
 
355
enum CdlInferenceCallbackResult {
356
    CdlInferenceCallbackResult_Continue = 0x01,
357
    CdlInferenceCallbackResult_Cancel   = 0x02
358
};
359
 
360
// ----------------------------------------------------------------------------
361
// Widget hints.
362
//
363
// The library can provide a hint to the GUI code as to a sensible
364
// widget to use for displaying a particular valuable. There are separate
365
// hints for the bool and data parts.
366
 
367
enum CdlBoolWidget {
368
    CdlBoolWidget_None                  = 0,    // The boolean part is not applicable
369
    CdlBoolWidget_CustomDialog          = 1,    // There is a valid custom dialog property
370
    CdlBoolWidget_CheckButton           = 2,    // For simple booleans
371
    CdlBoolWidget_Radio                 = 3,    // For several mutual exclusive options,
372
                                                // the data structure will provide a string identifier
373
};
374
 
375
enum CdlValueWidget {
376
    CdlValueWidget_None                 = 0,    // The value part is not applicable
377
    CdlValueWidget_CustomDialog         = 1,    // There is a valid custom dialog property
378
    CdlValueWidget_Loadable             = 2,    // Use package/version dialog
379
    CdlValueWidget_EntryBox             = 3,    // Fallback
380
    CdlValueWidget_MultilineString      = 4,    // For complicated strings
381
    CdlValueWidget_DecimalRange         = 5,    // e.g. 1 to 16
382
                                                // Could be implemented as scale, radio buttons, entry, pull-down menu,
383
                                                // combo box, ... depending on GUI conventions and number of entries
384
    CdlValueWidget_HexRange             = 6,    // e.g. 0x01 to 0x10
385
    CdlValueWidget_OctalRange           = 7,    // e.g. 01 to 020
386
    CdlValueWidget_DoubleRange          = 8,    // e.g. 0.1 to 0.2
387
    CdlValueWidget_NumericSet           = 9,    // e.g. 1 2 4 8 16
388
                                                // The exact nature of the numbers is irrelevant, they will only
389
                                                // get displayed, not edited
390
                                                // Could be implemented as radio buttons, entry widget, pull-down menu,
391
                                                // combo box, ... depending on GUI conventions and number of entries
392
                                                // Each entry can have its own representation
393
    CdlValueWidget_StringSet            = 10    // e.g. "ram", "rom"
394
 
395
    // More to be added, e.g. for compiler flag handling
396
};
397
 
398
// ----------------------------------------------------------------------------
399
// Value formats.
400
//
401
// The CDL input data can accept numbers in a variety of formats,
402
// for example hexadecimal as well as decimal. It is desirable to try
403
// to keep track of this formatting information where possible, so
404
// that what the user sees and what ends up in header files corresponds
405
// more closely to what is in the raw CDL data. For example, it is
406
// much easier to understand 0x7fffffff than its decimal equivalent.
407
//
408
// The information kept here is very imprecise, it provides only
409
// minimal formatting information. It is not clear yet whether this
410
// will suffice or whether something more exact is going to be needed.
411
enum CdlValueFormat
412
{
413
    CdlValueFormat_Default              = 0,
414
    CdlValueFormat_Hex                  = 1,
415
    CdlValueFormat_Octal                = 2
416
};
417
 
418
//}}}
419
//{{{  Exception classes
420
 
421
// ----------------------------------------------------------------------------
422
// Some parts of the library make use of C++ exception handling. A number
423
// of exception classes related to this library are useful. In addition
424
// just about every part of the library can throw std::bad_alloc, but this
425
// is not checked for explicitly anywhere.
426
 
427
// This class is used for all exceptions where an error message should
428
// be displayed to the user. There is a single string message associated
429
// with the exception.
430
 
431
class CdlStringException {
432
    friend class CdlTest;
433
 
434
  public:
435
    CdlStringException(std::string message_arg) {
436
        message = message_arg;
437
    }
438
    CdlStringException(const CdlStringException& original) {
439
        message = original.message;
440
    }
441
    CdlStringException& operator=(const CdlStringException& original) {
442
        message = original.message;
443
        return *this;
444
    }
445
    ~CdlStringException() {
446
        message = "";
447
    }
448
    const std::string& get_message() const {
449
        return message;
450
    }
451
  private:
452
    std::string message;
453
    CdlStringException();
454
};
455
 
456
// CdlInputOutputException: this gets thrown when something goes wrong during
457
// file I/O operations, e.g. a file exists but cannot be opened. The
458
// exception contains a simple string explaining the error. This string
459
// may contain multiple lines, it is intended to be written to stderr
460
// or displayed in either a text widget or a dialog box.
461
//
462
// A separate class rather than a typedef is used to avoid any possible
463
// error message confusion. Everything gets inlined so there should be
464
// no performance issues.
465
 
466
class CdlInputOutputException : public CdlStringException {
467
    friend class CdlTest;
468
  public:
469
    CdlInputOutputException(std::string message_arg) :
470
        CdlStringException(message_arg) {
471
    }
472
    CdlInputOutputException(const CdlInputOutputException& original) :
473
        CdlStringException(original) {
474
    }
475
    CdlInputOutputException& operator=(const CdlInputOutputException& original) {
476
        (void) CdlStringException::operator=(original);
477
        return *this;
478
    }
479
};
480
 
481
// This class is used when any parsing happens at the C++ level rather
482
// than at the Tcl level. The exception should be caught before it
483
// propagates through the Tcl interpreter, or the latter will end up
484
// in an inconsistent state.
485
 
486
class CdlParseException : public CdlStringException {
487
    friend class CdlTest;
488
  public:
489
    CdlParseException(std::string message_arg) :
490
        CdlStringException(message_arg) {
491
    }
492
    CdlParseException(const CdlParseException& original) :
493
        CdlStringException(original) {
494
    }
495
    CdlParseException& operator=(const CdlParseException& original) {
496
        (void) CdlStringException::operator=(original);
497
        return *this;
498
    }
499
};
500
 
501
// Evaluating an expression may fail for a variety of reasons, e.g. because
502
// some referenced entity has not been loaded into the configuration.
503
// This exception can be thrown in such cases.
504
 
505
class CdlEvalException : public CdlStringException {
506
    friend class CdlTest;
507
  public:
508
    CdlEvalException(std::string message_arg) :
509
        CdlStringException(message_arg) {
510
    }
511
    CdlEvalException(const CdlEvalException& original) :
512
        CdlStringException(original) {
513
    }
514
    CdlEvalException& operator=(const CdlEvalException& original) {
515
        (void) CdlStringException::operator=(original);
516
        return *this;
517
    }
518
};
519
 
520
//}}}
521
//{{{  Forward declarations of the body classes
522
 
523
// ----------------------------------------------------------------------------
524
// This section provides forward declarations of the main classes in
525
// the core of the library. Each variant of CDL will define additional
526
// classes, e.g. cdl_option, but these will usually be derived from
527
// the core ones.
528
 
529
// There are three types of expression in CDL:
530
// 1) ordinary expressions evaluate to a single value. The most common
531
//    use is for the legal_values property.
532
// 2) list expressions evaluate to a range of values, e.g. 1 to 10,
533
//    and the most common use is for the legal_values property.
534
// 3) goal expressions evaluate to either true or false and are used
535
//    for e.g. requires and active_if properties.
536
class CdlExpressionBody;
537
class CdlListExpressionBody;
538
class CdlGoalExpressionBody;
539
 
540
// There are also objects for simple values, values and list values.
541
// These are expanded classes, there are no associated pointer
542
// types. It is quite likely that values need to be copied around
543
// on the stack.
544
class CdlSimpleValue;
545
class CdlValue;
546
class CdlListValue;
547
 
548
// Properties. The base class is CdlProperty, and there are a number
549
// of derived classes provided as standard. Additional derived classes
550
// may be added in future.
551
class CdlPropertyBody;
552
class CdlProperty_MinimalBody;
553
class CdlProperty_StringBody;
554
class CdlProperty_TclCodeBody;
555
class CdlProperty_ReferenceBody;
556
class CdlProperty_StringVectorBody;
557
class CdlProperty_ExpressionBody;
558
class CdlProperty_ListExpressionBody;
559
class CdlProperty_GoalExpressionBody;
560
 
561
// Base classes. CDL entities such as options and components derive
562
// from one or more of these, using virtual inheritance.
563
//
564
// The lowest-level class is CdlNodeBody.
565
//
566
// 1) a node usually lives in a hierarchy, below a toplevel
567
//    and with a container object as the parent. However nodes
568
//    can live outside a container on a temporary basis,
569
//    and toplevel objects have no parent.
570
//
571
// 2) a node has a name that is unique within the hierarchy.
572
//
573
// 3) a node has a vector of properties. Actually some entities
574
//    will have an empty vector, e.g. the orphans container
575
//    that is internal to the library. However it is too
576
//    inconvenient to have separate base classes for these.
577
//
578
// 4) nodes can be referred to by properties in other nodes.
579
class CdlNodeBody;
580
 
581
// A container is a node that can contain other nodes.
582
class CdlContainerBody;
583
 
584
// A loadable object is a container whose data has come out of a CDL
585
// script of some sort. It also stores details about all entities that
586
// were loaded via this script (even if some of them were reparented)
587
// thus supporting unload operations.
588
class CdlLoadableBody;
589
 
590
// A toplevel object is a container that acts as the toplevel of
591
// a hierarchy, in other words its parent is always 0. In addition
592
// a toplevel keeps track of all the names used in the hierarchy,
593
// thus facilitating navigation.
594
class CdlToplevelBody;
595
 
596
// The remaining classes all add functionality to CdlNode, directly or
597
// indirectly.
598
//
599
// A user-visible object is likely to appear in the user interface.
600
// This means it may have an alias string, a description, a
601
// documentation URL, and a gui_hint field.
602
class CdlUserVisibleBody;
603
 
604
// A valuable object has a value that can be retrieved but not
605
// necessarily modified by the user. For example the value of an
606
// interface is always calculated and users can never change it.
607
// Valuable objects have a whole bunch of associated properties
608
// including dependencies.
609
class CdlValuableBody;
610
 
611
// A parentable object has the parent property, i.e. it can
612
// be reparented to anywhere in the hierarchy
613
class CdlParentableBody;
614
 
615
// A buildable object is a valuable object that may result in
616
// something being built, typically a library in the case of
617
// software packages.
618
class CdlBuildableBody;
619
 
620
// A loadable that contains buildables
621
class CdlBuildLoadableBody;
622
 
623
// A definable object is a valuable object whose value can result
624
// in #define statements in a header file
625
class CdlDefinableBody;
626
 
627
// A loadable which can contain definables
628
class CdlDefineLoadableBody;
629
 
630
// TODO: add instantiation support
631
 
632
// Custom dialogs and wizards are provided by the core.
633
class CdlDialogBody;
634
class CdlWizardBody;
635
class CdlInterfaceBody;
636
 
637
// Support for Tcl interpreters is also in the core, since it is
638
// difficult to do anything CDL-related without at least one Tcl
639
// interpreter lying around.
640
class CdlInterpreterBody;
641
 
642
// The basic conflict class is part of the core library, as are a
643
// number of common derived classes for specific types of conflict.
644
class CdlConflictBody;
645
class CdlConflict_UnresolvedBody;
646
class CdlConflict_IllegalValueBody;
647
class CdlConflict_EvalExceptionBody;
648
class CdlConflict_RequiresBody;
649
class CdlConflict_DataBody;
650
 
651
// Many operations happen (or may happen) in the context of a
652
// transaction. This is necessary to keep track of the various
653
// changes that can happen: for example, changing a component's
654
// value may require other entities' default values to be
655
// recalculated; it may change some legal_values list expressions,
656
// causing current values to become invalid; it may affect
657
// "requires" properties, causing goals to become satisfied or
658
// not-satisfied; it may change the "active" state of everything
659
// below the component, not to mention any entity with an
660
// "active_if" properties, and when an entity becomes active or
661
// inactive that may in turn affect other entities.
662
//
663
// Keeping track of all of this via recursion is possible, but there
664
// are problems. If an entity is updated multiple times, no
665
// optimizations are possible. It becomes much more difficult to
666
// detect cycles. During an unload operation things can get very
667
// messy. There is no easy way to track all of the changes and report
668
// them to higher level code via a callback. There is no support
669
// for any kind of rollback. A transaction model potentially
670
// provides support for all of this, at the cost of a more
671
// complex API.
672
class CdlTransactionBody;
673
 
674
// This class is used to pass information back to the application
675
// about what has actually changed in a transaction.
676
class CdlTransactionCallback;
677
 
678
 
679
// Build info class. This is always an expanded object, but is
680
// needed here to break a circular dependency.
681
class CdlBuildInfo;
682
 
683
// ----------------------------------------------------------------------------
684
// Typedefs for the pointers. There are separate typedefs to cope with
685
// const vs. non-const objects. Otherwise you end up with the problem
686
// that "const CdlNode x" means that the pointer is const, not the
687
// object pointed at.
688
 
689
typedef CdlExpressionBody*              CdlExpression;
690
typedef CdlListExpressionBody*          CdlListExpression;
691
typedef CdlGoalExpressionBody*          CdlGoalExpression;
692
 
693
typedef CdlPropertyBody*                CdlProperty;
694
typedef CdlProperty_MinimalBody*        CdlProperty_Minimal;
695
typedef CdlProperty_StringBody*         CdlProperty_String;
696
typedef CdlProperty_TclCodeBody*        CdlProperty_TclCode;
697
typedef CdlProperty_ReferenceBody*      CdlProperty_Reference;
698
typedef CdlProperty_StringVectorBody*   CdlProperty_StringVector;
699
typedef CdlProperty_ExpressionBody*     CdlProperty_Expression;
700
typedef CdlProperty_ListExpressionBody* CdlProperty_ListExpression;
701
typedef CdlProperty_GoalExpressionBody* CdlProperty_GoalExpression;
702
 
703
typedef CdlNodeBody*                    CdlNode;
704
typedef CdlContainerBody*               CdlContainer;
705
typedef CdlLoadableBody*                CdlLoadable;
706
typedef CdlToplevelBody*                CdlToplevel;
707
typedef CdlUserVisibleBody*             CdlUserVisible;
708
typedef CdlValuableBody*                CdlValuable;
709
typedef CdlParentableBody*              CdlParentable;
710
typedef CdlBuildableBody*               CdlBuildable;
711
typedef CdlBuildLoadableBody*           CdlBuildLoadable;
712
typedef CdlDefinableBody*               CdlDefinable;
713
typedef CdlDefineLoadableBody*          CdlDefineLoadable;
714
 
715
typedef CdlDialogBody*                  CdlDialog;
716
typedef CdlWizardBody*                  CdlWizard;
717
typedef CdlInterfaceBody*               CdlInterface;
718
 
719
typedef CdlInterpreterBody*             CdlInterpreter;
720
 
721
typedef CdlConflictBody*                CdlConflict;
722
typedef CdlConflict_UnresolvedBody*     CdlConflict_Unresolved;
723
typedef CdlConflict_IllegalValueBody*   CdlConflict_IllegalValue;
724
typedef CdlConflict_EvalExceptionBody*  CdlConflict_EvalException;
725
typedef CdlConflict_RequiresBody*       CdlConflict_Requires;
726
typedef CdlConflict_DataBody*           CdlConflict_Data;
727
 
728
typedef CdlTransactionBody*             CdlTransaction;
729
 
730
// ----------------------------------------------------------------------------
731
 
732
typedef const CdlExpressionBody*              CdlConstExpression;
733
typedef const CdlListExpressionBody*          CdlConstListExpression;
734
typedef const CdlGoalExpressionBody*          CdlConstGoalExpression;
735
 
736
typedef const CdlPropertyBody*                CdlConstProperty;
737
typedef const CdlProperty_MinimalBody*        CdlConstProperty_Minimal;
738
typedef const CdlProperty_StringBody*         CdlConstProperty_String;
739
typedef const CdlProperty_TclCodeBody*        CdlConstProperty_TclCode;
740
typedef const CdlProperty_ReferenceBody*      CdlConstProperty_Reference;
741
typedef const CdlProperty_StringVectorBody*   CdlConstProperty_StringVector;
742
typedef const CdlProperty_ExpressionBody*     CdlConstProperty_Expression;
743
typedef const CdlProperty_ListExpressionBody* CdlConstProperty_ListExpression;
744
typedef const CdlProperty_GoalExpressionBody* CdlConstProperty_GoalExpression;
745
 
746
typedef const CdlNodeBody*                    CdlConstNode;
747
typedef const CdlContainerBody*               CdlConstContainer;
748
typedef const CdlLoadableBody*                CdlConstLoadable;
749
typedef const CdlToplevelBody*                CdlConstToplevel;
750
typedef const CdlUserVisibleBody*             CdlConstUserVisible;
751
typedef const CdlValuableBody*                CdlConstValuable;
752
typedef const CdlParentableBody*              CdlConstParentable;
753
typedef const CdlBuildableBody*               CdlConstBuildable;
754
typedef const CdlBuildLoadableBody*           CdlConstBuildLoadable;
755
typedef const CdlDefinableBody*               CdlConstDefinable;
756
typedef const CdlDefineLoadableBody*          CdlConstDefineLoadable;
757
 
758
typedef const CdlDialogBody*                  CdlConstDialog;
759
typedef const CdlWizardBody*                  CdlConstWizard;
760
typedef const CdlInterfaceBody*               CdlConstInterface;
761
 
762
typedef const CdlInterpreterBody*             CdlConstInterpreter;
763
 
764
typedef const CdlConflictBody*                CdlConstConflict;
765
typedef const CdlConflict_UnresolvedBody*     CdlConstConflict_Unresolved;
766
typedef const CdlConflict_IllegalValueBody*   CdlConstConflict_IllegalValue;
767
typedef const CdlConflict_EvalExceptionBody*  CdlConstConflict_EvalException;
768
typedef const CdlConflict_RequiresBody*       CdlConstConflict_Requires;
769
typedef const CdlConflict_DataBody*           CdlConstConflict_Data;
770
 
771
typedef const CdlTransactionBody*             CdlConstTransaction;
772
 
773
//}}}
774
//{{{  Miscellaneous types etc.
775
 
776
// ----------------------------------------------------------------------------
777
// This section is used for data types, function prototypes, etc. which could
778
// not be defined until after the main CDL classes and handles.
779
 
780
// This typedef is used for error and warning reporting functions.
781
// Typically such a function pointer will be passed when the library
782
// is asked to perform any non-trivial parsing operation, e.g. loading
783
// a package.
784
//
785
// If the error is fatal then this callback function should raise
786
// a CdlParseException.
787
typedef void (*CdlDiagnosticFnPtr)(std::string);
788
 
789
// ----------------------------------------------------------------------------
790
// This function is used for update handler. Whenever there is a change
791
// to CDL entity (it has just been loaded, or its value has changed, or
792
// whatever) this can affect other CDL entities that reference it.
793
// All such references occur via properties, and there should be
794
// update handlers associated with those properties.
795
//
796
// Update handlers are also invoked for initialization and finalization
797
// operations, i.e. when the source object itself has just been loaded
798
// or is in the process of being unloaded.
799
//
800
// The arguments to an update handler are:
801
// 1) the transaction in which the operation takes place
802
// 2) the source object containing the reference
803
// 3) the source property containing the reference
804
// 4) the destination object. This may be 0 for some update
805
//    operations.
806
// 5) an indication of the change that has happened. This should
807
//    be a CdlUpdate value.
808
typedef void (*CdlUpdateHandler)(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
809
 
810
// ----------------------------------------------------------------------------
811
// This function is also used for transactions. Typically during a
812
// transaction there will be one or more invocations of the inference engine,
813
// with callbacks in between to allow one or more of the recommended
814
// changes to be undone.
815
typedef CdlInferenceCallbackResult (*CdlInferenceCallback)(CdlTransaction);
816
 
817
// ----------------------------------------------------------------------------
818
// The TCL API and C++ do not always mesh cleanly, for example a lot
819
// happens in terms of ClientData which is a void* pointer. To avoid
820
// too many casts all over the place libcdl provides a CdlInterpreter
821
// class and the following alternative to Tcl_CmdProc*. A single
822
// function will be used for the TCL command: its ClientData will be
823
// the CdlInterpreterCommand, and the CdlInterpreter is accessible via
824
// AssocData. This does result in some overheads, but none of these
825
// should be in performance-critical code.
826
typedef int (*CdlInterpreterCommand)(CdlInterpreter, int, const char*[]);
827
 
828
// ----------------------------------------------------------------------------
829
// In the libcdl world it is often convenient to swap whole sets of
830
// commands in and out. For example when executing the body of a
831
// cdl_component it is desirable to swap in commands for all the
832
// properties that make sense in a component and swap out all the
833
// commands that made sense in a higher level. It is assumed that none
834
// of the commands being swapped in or out are built-ins. Achieving
835
// this involves a vector of this simple utility structure.
836
class CdlInterpreterCommandEntry {
837
  public:
838
    std::string                 name;
839
    CdlInterpreterCommand       command;
840
 
841
    CdlInterpreterCommandEntry() : name(""), command(0) {}
842
    CdlInterpreterCommandEntry(const char *name_arg, CdlInterpreterCommand command_arg)
843
        : name(name_arg), command(command_arg)
844
    {
845
    }
846
    CdlInterpreterCommandEntry(std::string name_arg, CdlInterpreterCommand command_arg)
847
        : name(name_arg), command(command_arg)
848
    {
849
    }
850
    ~CdlInterpreterCommandEntry()
851
    {
852
        name = "";
853
        command = 0;
854
    }
855
};
856
 
857
// ----------------------------------------------------------------------------
858
// Persistence support.
859
// Some applications want to be able to store additional information
860
// in savefiles, and essentially this involves extra commands that
861
// get executed when the savefile is executed. It is possible that
862
// the application reading back the savefile does not understand
863
// the same set of commands as the application that wrote back the
864
// data, so the library tries hard not to lose data.
865
//
866
// The CdlSaveCallback function typedef is used when installing
867
// an application-specific savefile command. The first argument
868
// indicates the node for which the callback is being invoked:
869
// this may be the entire toplevel, or just an option, or whatever.
870
//
871
// The CdlSavefileCommand structure keeps track of the command,
872
// the save callback if any (non-zero only for application-specific
873
// data, zero implies that the command is handled by the lirary).
874
// The load command is invoked when reading in a savefile and the
875
// appropriate command is executed: unrecognised commands will be
876
// processed by CdlToplevelBody::savefile_handle_unknown().
877
 
878
typedef void (*CdlSaveCallback)(CdlNode, CdlInterpreter, Tcl_Channel, int);
879
 
880
struct CdlSavefileCommand {
881
    std::string           name;
882
    CdlSaveCallback       save_callback;
883
    CdlInterpreterCommand load_command;
884
};
885
 
886
// ----------------------------------------------------------------------------
887
// Widget hint.
888
// This structure provides widget hint information for a CdlValuable.
889
// There are separate hints for the bool and data parts, and possibly
890
// some additional data such as a string identifying the set of
891
// items in a radio button.
892
struct CdlWidgetHint {
893
    CdlBoolWidget       bool_widget;
894
    CdlValueWidget      value_widget;
895
    std::string         radio_button_interface;
896
};
897
 
898
//}}}
899
//{{{  Memory leak detection
900
 
901
// ----------------------------------------------------------------------------
902
// Provide some macros that are useful for detecting memory leaks. Basically
903
// there is a static counter for every class, which gets incremented by the
904
// constructor(s) and decremented by the destructor. Memory leak detection
905
// is currently enabled if tracing is enabled. It would be possible to use
906
// another configure-time option, but the overheads of tracing are likely
907
// to dwarf the overheads of memory leak detection.
908
//
909
// For now the memleak counters are always present, even in non-debug
910
// versions. The overhead is sufficiently small that it can be
911
// ignored.There is control over whether or not the counters get
912
// updated in the constructor or destructor. Otherwise there would be problems
913
// with whether or not there should be a semicolon at the end of the
914
// CYGDBG_DECLARE_MEMLEAK_COUNTER() macro definition.
915
 
916
#define CYGDBG_DECLARE_MEMLEAK_COUNTER()        static int memleak_counter
917
#define CYGDBG_DEFINE_MEMLEAK_COUNTER(class)    int class::memleak_counter = 0
918
#define CYGDBG_GET_MEMLEAK_COUNTER(class)       class::memleak_counter
919
 
920
#ifdef CYGDBG_USE_TRACING
921
 
922
#define CYGDBG_MEMLEAK_CONSTRUCTOR()            this->memleak_counter++;
923
#define CYGDBG_MEMLEAK_DESTRUCTOR()             this->memleak_counter--;
924
#define CYGDBG_MEMLEAK_CHECKTHIS()              if (this->memleak_counter < 0) { return false; }
925
 
926
#else
927
 
928
#define CYGDBG_MEMLEAK_CONSTRUCTOR()
929
#define CYGDBG_MEMLEAK_DESTRUCTOR()
930
#define CYGDBG_MEMLEAK_CHECKTHIS()
931
 
932
#endif
933
 
934
//}}}
935
 
936
//{{{  Cdl class
937
 
938
// ---------------------------------------------------------------------------
939
// The sole purpose of this class is to provide some utility functions with
940
// reasonable namespace protection, without requiring that the compiler
941
// implements namespaces.
942
 
943
class Cdl {
944
 
945
  public:
946
 
947
    static bool         is_valid_value_flavor(CdlValueFlavor);
948
    static bool         is_valid_value_source(CdlValueSource);
949
 
950
    static bool         is_valid_cdl_name(const std::string&);
951
    static bool         is_valid_c_preprocessor_symbol(const std::string&);
952
 
953
    static bool         string_to_integer(std::string, cdl_int&);
954
    static bool         string_to_double(std::string, double&);
955
    static bool         string_to_bool(std::string, bool&);
956
    static void         integer_to_string(cdl_int, std::string&, CdlValueFormat = CdlValueFormat_Default);
957
    static std::string  integer_to_string(cdl_int, CdlValueFormat = CdlValueFormat_Default);
958
    static void         double_to_string(double, std::string&, CdlValueFormat = CdlValueFormat_Default);
959
    static std::string  double_to_string(double, CdlValueFormat = CdlValueFormat_Default);
960
    static void         bool_to_string(bool, std::string&);
961
    static std::string  bool_to_string(bool);
962
    static void         integer_to_double(cdl_int, double&);
963
    static double       integer_to_double(cdl_int);
964
    static bool         double_to_integer(double, cdl_int&);
965
 
966
    static bool         string_to_flavor(std::string, CdlValueFlavor&);
967
    static bool         flavor_to_string(CdlValueFlavor, std::string&);
968
    static bool         string_to_source(std::string, CdlValueSource&);
969
    static bool         source_to_string(CdlValueSource, std::string&);
970
 
971
    static std::string  get_library_version();
972
    static void         set_interactive(bool = true);
973
    static bool         is_interactive();
974
 
975
    static bool         truth() { return true; }
976
    static bool         falsehood() { return false; }
977
 
978
    // return values are -1,0,1 just like strcmp(). The most recent
979
    // version is the smallest.
980
    static int          compare_versions(std::string, std::string);
981
 
982
    // Also provide an STL-friendly comparison class
983
    class version_cmp {
984
      public:
985
        bool operator()(const std::string& v1, const std::string& v2) const {
986
            return Cdl::compare_versions(v1,v2) < 0;
987
        }
988
    };
989
 
990
    // Split a version string into major, minor and release numbers.
991
    static void         split_version_string(const std::string&, std::string& /* major */,
992
                                             std::string& /* minor */, std::string& /* release */);
993
 
994
    // It is occasionally useful to take a full CDL name such as CYGPKG_KERNEL
995
    // and turn it into a short form, i.e. kernel.
996
    static std::string  get_short_form(const std::string&);
997
 
998
  private:
999
    static bool         interactive;
1000
};
1001
 
1002
//}}}
1003
//{{{  CdlInterpreter class
1004
 
1005
// ----------------------------------------------------------------------------
1006
// libcdl requires access to a Tcl interpreter. For now the standard
1007
// interpreter is used. In the long run it may be better to use a
1008
// custom parser in places, if only to improve the diagnostics messages
1009
// that users see.
1010
//
1011
// Consider the case of software CDL (other CDL variants will have
1012
// similar requirements). A Tcl interpreter is needed to read in the
1013
// data for a given package. It will also be needed at various stages
1014
// when the data is being manipulated, e.g. to display a custom dialog
1015
// or to execute e.g. a check_proc or a define_proc. Each package
1016
// should run in its own safe interpreter with limited capabilities:
1017
// file I/O is limited to read-only, but read-write in the build and
1018
// install trees; network I/O is out of the question, at least until
1019
// appropriate security support is added to the CDL language itself.
1020
// However the interpreter should be extended with additional commands
1021
// like cdl_get and cdl_set to access the configuration data.
1022
//
1023
// For security and robustness reasons it is desirable to have
1024
// separate interpreters for the various packages. This leads to the
1025
// concept of a master interpreter for the entire configuration, and a
1026
// group of slave interpreters, one per package. In this model it
1027
// is convenient to have the configuration and package entities
1028
// associated directly with the interpreter. Note that a single
1029
// application may have several configurations loaded in memory,
1030
// so there may be several master interpreters.
1031
//
1032
// Some applications will want to support the graphical side of CDL,
1033
// i.e. custom dialogs and wizards. This means linking in Tk, not to
1034
// mention X11 (or the Windows equivalents), and making some/all of
1035
// the Tk commands available to the safe interpreter. Arguably
1036
// commands like toplevel should always be disabled. Not all clients
1037
// of libcdl will want the overheads of linking with Tk and X, so this
1038
// has to be made optional.
1039
//
1040
// The approach taken is as follows:
1041
//
1042
// 1) there is a class CdlInterpreter which provides access to Tcl
1043
//    interpreters. Amongst other things it takes care of converting
1044
//    between C and C++ strings.
1045
//
1046
// 2) every toplevel needs its own CdlInterpreter. The application
1047
//    code should supply this interpreter itself when the toplevel
1048
//    is instantiated, allowing it to decide whether or not Tk should
1049
//    be available.
1050
//
1051
// 3) each loadable gets its own safe slave interpreter, derived from
1052
//    the toplevel's interpreter.
1053
//    NOTE: initially the slave interpreters are not actually safe. It
1054
//    is not clear in the long term to what extent per-loadable
1055
//    interpreters need to be sandboxes, there are issues such as
1056
//    doing the equivalent of autoconf tests.
1057
 
1058
// Tcl 8.4 involved various incompatible API changes related to
1059
// const vs. non-const data. #define'ing USE_NON_CONST or
1060
// USE_COMPAT_CONST avoids some of the problems, but does not
1061
// help much for C++.
1062
#if (TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))
1063
# define CDL_TCL_CONST_CAST(type,var) (var)
1064
#else
1065
# define CDL_TCL_CONST_CAST(type,var) const_cast(var)
1066
#endif
1067
 
1068
class CdlInterpreterBody
1069
{
1070
    friend class        CdlTest;
1071
 
1072
  public:
1073
 
1074
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
1075
 
1076
    // This is how a top-level (i.e. per-toplevel) interpreter
1077
    // should get created.
1078
    static CdlInterpreter       make(Tcl_Interp* = 0);
1079
 
1080
    // Create a slave interpreter for reading in the data in e.g. a
1081
    // cdl_package
1082
    CdlInterpreter create_slave(CdlLoadable, bool /* safe */ = true);
1083
 
1084
    // Make the interpreter safe, a one-way operation.
1085
    void                make_safe();
1086
 
1087
    // The destructor is public.
1088
    virtual ~CdlInterpreterBody();
1089
 
1090
    // Add or remove commands from an interpreter. This provides
1091
    // a more C++-friendly implementation of Tcl's
1092
    // CreateCommand() and DeleteCommand().
1093
    void add_command(std::string, CdlInterpreterCommand);
1094
    void remove_command(std::string);
1095
 
1096
    // In the libcdl world it is also convenient to swap whole sets of
1097
    // commands in and out. This is achieved by push and pop operations.
1098
    // push returns the old set (0 at the toplevel). pop restores
1099
    // the old set.
1100
    std::vector* push_commands(std::vector&);
1101
    void pop_commands(std::vector*);
1102
    std::vector* get_pushed_commands() const;
1103
 
1104
    // Similarly, allow variables to be set, unset and queried
1105
    void        set_variable(std::string, std::string);
1106
    void        unset_variable(std::string);
1107
    std::string get_variable(std::string);
1108
 
1109
    // FIXME: add support for variable traces. These are needed
1110
    // for cdl_value and similar utilities.
1111
 
1112
    // Provide hooks into the AssocData() facilities associated with
1113
    // Tcl interpreters. This makes it possible to store arbitrary
1114
    // data with an interpreter, e.g. to keep track of current state.
1115
    void       set_assoc_data(const char*, ClientData, Tcl_InterpDeleteProc* =0);
1116
    void       delete_assoc_data(const char*);
1117
    ClientData get_assoc_data(const char*);
1118
 
1119
    // Evaluate a string as Tcl code. The return value comes from Tcl, e.g.
1120
    // TCL_OK or TCL_ERROR. There are variants depending on whether or not
1121
    // the result string is of interest.
1122
    int eval(std::string);
1123
    int eval(std::string, std::string&);
1124
 
1125
    // Ditto for any Tcl code that comes from CDL files
1126
    int eval_cdl_code(const cdl_tcl_code);
1127
    int eval_cdl_code(const cdl_tcl_code, std::string&);
1128
 
1129
    // And support for evaluating an entire file
1130
    int eval_file(std::string);
1131
    int eval_file(std::string, std::string&);
1132
 
1133
    // For use by commands implemented in C++, a way of setting the result
1134
    void set_result(std::string);
1135
 
1136
    // And a utility to get the result as well.
1137
    std::string get_result();
1138
 
1139
    // Was the result set by the Tcl interpreter or by libcdl?
1140
    bool result_set_by_cdl();
1141
 
1142
    // A utility to quote data that is going to end up in a TCL script.
1143
    static std::string quote(std::string);
1144
 
1145
    // Turn some multiline data into a comment.
1146
    static std::string multiline_comment(const std::string&, int, int = 0);
1147
 
1148
    // Add some data to a comment, allowing for newlines if necessary
1149
    static std::string extend_comment(const std::string&, int, int = 0);
1150
 
1151
    // Write some data to a savefile, throwing an exception on error
1152
    void write_data(Tcl_Channel, std::string);
1153
 
1154
    // File-related utilities.
1155
    void locate_subdirs(std::string, std::vector&);
1156
    void locate_all_subdirs(std::string, std::vector&);
1157
    void locate_files(std::string, std::vector&);
1158
    void locate_all_files(std::string, std::vector&);
1159
    bool is_directory(std::string);
1160
    bool is_file(std::string);
1161
 
1162
    // When parsing a CDL script it is convenient to keep track of
1163
    // a number of items:
1164
    //
1165
    // 1) the toplevel, e.g. the entire configuration
1166
    // 2) the loadable, e.g. the current package
1167
    // 3) the parent of whatever is being processed at the moment
1168
    // 4) the entity, i.e. the thingamajig that is being processed.
1169
    // 5) the current file
1170
    // 6) an error reporting function
1171
    //
1172
    // This gives the various commands embedded in the Tcl interpreter
1173
    // enough information to do their job. Additional information can
1174
    // be provided via assoc_data()
1175
    //
1176
    // There should be only one call to set_toplevel(), for the
1177
    // master interpreter. All slaves inherit this, and the toplevel
1178
    // cannot be changed again.
1179
    //
1180
    // The loadable field is filled in via make_slave()
1181
    //
1182
    // For some members push and pop functions are more appropriate
1183
    // than set.
1184
    CdlToplevel         get_toplevel() const;
1185
    CdlLoadable         get_loadable() const;
1186
    CdlContainer        get_container() const;
1187
    CdlNode             get_node() const;
1188
    std::string         get_context() const;
1189
    CdlDiagnosticFnPtr  get_error_fn_ptr() const;
1190
    CdlDiagnosticFnPtr  get_warning_fn_ptr() const;
1191
    CdlTransaction      get_transaction() const;
1192
    void                set_toplevel(CdlToplevel);
1193
    void                set_transaction(CdlTransaction);
1194
    CdlContainer        push_container(CdlContainer);
1195
    void                pop_container(CdlContainer);
1196
    CdlNode             push_node(CdlNode);
1197
    void                pop_node(CdlNode);
1198
    std::string         push_context(std::string);
1199
    void                pop_context(std::string);
1200
    CdlDiagnosticFnPtr  push_error_fn_ptr(CdlDiagnosticFnPtr);
1201
    void                pop_error_fn_ptr(CdlDiagnosticFnPtr);
1202
    CdlDiagnosticFnPtr  push_warning_fn_ptr(CdlDiagnosticFnPtr);
1203
    void                pop_warning_fn_ptr(CdlDiagnosticFnPtr);
1204
 
1205
    // Provide utility classes for common push/pop combinations. The
1206
    // push happens during the constructor, the pop during the
1207
    // destructor. This can simplify some code, especially when
1208
    // exceptions may get thrown.
1209
    class DiagSupport {
1210
      public:
1211
        DiagSupport(CdlInterpreter interp_arg, CdlDiagnosticFnPtr error_fn_arg, CdlDiagnosticFnPtr warn_fn_arg) {
1212
            interp         = interp_arg;
1213
            saved_error_fn = interp->push_error_fn_ptr(error_fn_arg);
1214
            saved_warn_fn  = interp->push_warning_fn_ptr(warn_fn_arg);
1215
        }
1216
        ~DiagSupport() {
1217
            interp->pop_error_fn_ptr(saved_error_fn);
1218
            interp->pop_warning_fn_ptr(saved_warn_fn);
1219
        }
1220
    private:
1221
        DiagSupport();
1222
 
1223
        CdlInterpreter     interp;
1224
        CdlDiagnosticFnPtr saved_error_fn;
1225
        CdlDiagnosticFnPtr saved_warn_fn;
1226
    };
1227
    class ContextSupport {
1228
      public:
1229
        ContextSupport(CdlInterpreter interp_arg, std::string context) {
1230
            interp = interp_arg;
1231
            saved_context = interp->push_context(context);
1232
        }
1233
        ~ContextSupport() {
1234
            interp->pop_context(saved_context);
1235
        }
1236
      private:
1237
        ContextSupport();
1238
        CdlInterpreter interp;
1239
        std::string    saved_context;
1240
    };
1241
    class ContainerSupport {
1242
      public:
1243
        ContainerSupport(CdlInterpreter interp_arg, CdlContainer container) {
1244
            interp = interp_arg;
1245
            saved_container = interp->push_container(container);
1246
        }
1247
        ~ContainerSupport() {
1248
            interp->pop_container(saved_container);
1249
        }
1250
      private:
1251
        ContainerSupport();
1252
        CdlInterpreter interp;
1253
        CdlContainer   saved_container;
1254
    };
1255
    class NodeSupport {
1256
      public:
1257
        NodeSupport(CdlInterpreter interp_arg, CdlNode node) {
1258
            interp = interp_arg;
1259
            saved_node = interp->push_node(node);
1260
        }
1261
        ~NodeSupport() {
1262
            interp->pop_node(saved_node);
1263
        }
1264
      private:
1265
        NodeSupport();
1266
        CdlInterpreter interp;
1267
        CdlNode        saved_node;
1268
    };
1269
    class CommandSupport {
1270
      public:
1271
        CommandSupport(CdlInterpreter interp_arg, std::vector& commands) {
1272
            interp = interp_arg;
1273
            saved_commands = interp->push_commands(commands);
1274
        }
1275
        CommandSupport(CdlInterpreter interp_arg, CdlInterpreterCommandEntry* commands) {
1276
            unsigned int i;
1277
            for (i = 0; 0 != commands[i].command; i++) {
1278
                new_commands.push_back(commands[i]);
1279
            }
1280
            interp = interp_arg;
1281
            saved_commands = interp->push_commands(new_commands);
1282
        }
1283
        ~CommandSupport() {
1284
            interp->pop_commands(saved_commands);
1285
        }
1286
 
1287
      private:
1288
        CommandSupport();
1289
        CdlInterpreter interp;
1290
        std::vector* saved_commands;
1291
        std::vector new_commands;
1292
    };
1293
 
1294
    // Similar utility classes for variables and assoc data.
1295
    class VariableSupport {
1296
      public:
1297
        VariableSupport(CdlInterpreter interp_arg, std::string varname_arg, std::string data) {
1298
            interp  = interp_arg;
1299
            varname = varname_arg;
1300
            interp->set_variable(varname, data);
1301
        }
1302
        ~VariableSupport() {
1303
            interp->unset_variable(varname);
1304
        }
1305
      private:
1306
        VariableSupport();
1307
        CdlInterpreter interp;
1308
        std::string    varname;
1309
    };
1310
    class AssocSupport {
1311
      public:
1312
        AssocSupport(CdlInterpreter interp_arg, const char* name_arg, ClientData data, Tcl_InterpDeleteProc* del_proc = 0) {
1313
            interp = interp_arg;
1314
            name   = name_arg;
1315
            interp->set_assoc_data(name, data, del_proc);
1316
        }
1317
        ~AssocSupport() {
1318
            interp->delete_assoc_data(name);
1319
        }
1320
      private:
1321
        AssocSupport();
1322
        CdlInterpreter interp;
1323
        const char*    name;
1324
    };
1325
 
1326
    // Some command implementations may want to access other Tcl library
1327
    // routines such as Tcl_SplitList(). This requires convenient access
1328
    // to the underlying Tcl interpreter.
1329
    Tcl_Interp*         get_tcl_interpreter() const;
1330
 
1331
    // For use by the assertion macros.
1332
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
1333
 
1334
  private:
1335
    // This is the Tcl command proc that gets registered for all
1336
    // CdlInterpreterCommand instances.
1337
    static int          tcl_command_proc(ClientData, Tcl_Interp*, int, const char*[]);
1338
 
1339
    // This key is used to access the CdlInterpreter assoc data.
1340
    static const char*  cdlinterpreter_assoc_data_key;
1341
 
1342
    // Do not allow static instances of a Cdl interpreter. There are too
1343
    // many possible failure conditions. Cdl interpreters can only be
1344
    // created dynamically via make(), which will invoke this.
1345
    CdlInterpreterBody(Tcl_Interp*);
1346
 
1347
    // Default constructor, copy constructor and assignment are illegal
1348
    CdlInterpreterBody();
1349
    CdlInterpreterBody(const CdlInterpreterBody&);
1350
    CdlInterpreterBody& operator=(const CdlInterpreterBody&);
1351
 
1352
 
1353
    Tcl_Interp*                 tcl_interp;     // The underlying Tcl interpreter
1354
    bool                        owns_interp;    // Was the Tcl interpreter created by the library?
1355
    std::vector slaves;         // All slave interpreters
1356
    CdlInterpreter              parent;         // Or else the parent
1357
    CdlToplevel                 toplevel;       // Data that gets used during the parsing process
1358
    CdlTransaction              transaction;
1359
    CdlLoadable                 loadable;
1360
    CdlContainer                container;
1361
    CdlNode                     node;
1362
    std::string                 context;
1363
    CdlDiagnosticFnPtr          error_fn_ptr;
1364
    CdlDiagnosticFnPtr          warning_fn_ptr;
1365
    bool                        cdl_result;
1366
 
1367
    std::vector* current_commands; // for push() and pop()
1368
 
1369
    enum {
1370
        CdlInterpreterBody_Invalid = 0,
1371
        CdlInterpreterBody_Magic   = 0x0be67689
1372
    } cdlinterpreterbody_cookie;
1373
};
1374
 
1375
//}}}
1376
//{{{  CdlReference/Referrer classes
1377
 
1378
// ---------------------------------------------------------------------------
1379
// CDL objects are organised primarily in a tree hierarchy. For
1380
// example a package contains components, components contain options,
1381
// and so on. The tree hierarchy tends to change rather infrequently,
1382
// so it makes sense to have a quick way of navigating between
1383
// entities without continuously having to do hash-table lookups. In
1384
// addition it is very desirable to make the connectivity
1385
// bidirectional: if a "requires" property in option A references
1386
// option B then it would be useful to have a link back to A from B;
1387
// that way, if the value of B changes it is a lot easier to keep
1388
// things up to date.
1389
//
1390
// Terminology: the entity which contains the reference, e.g. a
1391
// "requires" property, is the source. The relevant property is the
1392
// "source property". The entity pointed at is the destination.
1393
//
1394
// Unfortunately there may be connections between CDL entities outside
1395
// the tree hierarchy. In particular any property can contain one or
1396
// more references to packages, components, options, wizards, or
1397
// whatever. Often these references will be to options etc. within the
1398
// same package, but some references will go to other packages. There
1399
// may even be references to other configurations: for example a board
1400
// may contain both an ordinary processor and a DSP; these two need
1401
// their own configurations; however a package running on the DSP may
1402
// need to interact with a package running on the processor, and vice
1403
// versa.
1404
//
1405
// Also, a reference may occur inside an object that is not in the
1406
// hierarchy. For example CDL expressions may get evaluated inside Tcl
1407
// code rather than as part of a property. Such expressions may still
1408
// contain references to entities in the current configuration.
1409
//
1410
// References may not be resolved. When reading in a CDL script there
1411
// may be forward references. A reference may involve another package
1412
// that has not yet been loaded, which is a conflict.
1413
//
1414
// Using simple pointers to store these connections is a bad idea. It
1415
// makes it a lot harder to figure out what is connected to what, and
1416
// it introduces horrible consistency problems when packages get
1417
// loaded and unloaded. Instead libCDL provides a CdlReference class.
1418
// Whenever a CdlProperty contains a reference to some other CDL
1419
// entity there should be a CdlReference object corresponding to this.
1420
// The reverse direction is handled via a CdlReferrer object.
1421
//
1422
// A CdlReference object can be either bound or unbound. By default it
1423
// is unbound, containing only a string. It can then be bound via a
1424
// member function, examined, and unbound again as required. Creating
1425
// a binding automatically creates a CdlReferrer entry in the target
1426
// object, thus avoiding any risk of inconsistencies.
1427
//
1428
// The CdlReference class should not be used outside the hierarchy,
1429
// since every bound reference must have a referrer object pointing
1430
// back, and this link back can only be valid within the hierarchy.
1431
// Temporary CdlReference objects are useful during the construction
1432
// of properties.
1433
//
1434
// It is possible that a given property (e.g. a complicated "requires"
1435
// expression) has multiple references to another entity. Each of
1436
// these involves a separate CdlReference/CdlReferrer pair.
1437
 
1438
// ----------------------------------------------------------------------------
1439
// The actual CdlReference class.
1440
 
1441
class CdlReference {
1442
 
1443
    friend class        CdlTest;
1444
 
1445
    // CdlReferrer must be a friend so that when a package gets unloaded
1446
    // it can clean up all references to it.
1447
    friend class        CdlReferrer;
1448
 
1449
  public:
1450
 
1451
    // The default constructor should not normally be used, instead
1452
    // a string should be supplied. However there are vectors of
1453
    // reference objects...
1454
    CdlReference();
1455
 
1456
    // The main constructor supplies the name of the referenced
1457
    // entity. The resulting object will be unbound.
1458
    CdlReference(const std::string);
1459
 
1460
    // The copy constructor is legal for unbound objects only.
1461
    CdlReference(const CdlReference&);
1462
 
1463
    // The assignment operator is needed for STL operations.
1464
    // Again it only makes sense of unbound objects.
1465
    CdlReference& operator=(const CdlReference&);
1466
 
1467
    // The destructor is only valid for unbound objects. All references
1468
    // should be unbound before an entity can be destroyed.
1469
    ~CdlReference();
1470
 
1471
    // Access the various fields.
1472
    void               set_destination_name(const std::string);
1473
    const std::string& get_destination_name() const;
1474
    CdlNode            get_destination() const;
1475
 
1476
    // Binding a reference. Obviously this can only be used when the
1477
    // reference is still unbound. When doing the binding it is
1478
    // necessary to know:
1479
    //   (1) the object containing the reference.
1480
    //   (2) the specific property that contains the reference.
1481
    //   (3) the object being referred to.
1482
    // Binding a reference results in a new referrer entry in the
1483
    // destination.
1484
    void bind(CdlNode, CdlProperty, CdlNode);
1485
 
1486
    // Unbinding a reference. Typically this only happens when the
1487
    // destination is unloaded. The arguments provide the source and
1488
    // the source property.
1489
    void unbind(CdlNode, CdlProperty);
1490
 
1491
    // This is used by the ASSERT_CLASS() and ASSERT_THIS() macros.
1492
    bool check_this(cyg_assert_class_zeal cyg_quick) const;
1493
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
1494
 
1495
  protected:
1496
 
1497
  private:
1498
 
1499
    // The data fields. The name is usually filled in by the
1500
    // constructor. The destination defaults to zero for an unbound
1501
    // object and gets filled in by the bind() operation.
1502
    std::string dest_name;
1503
    CdlNode     dest;
1504
 
1505
    enum {
1506
        CdlReference_Invalid = 0,
1507
        CdlReference_Magic   = 0x3f908608
1508
    } cdlreference_cookie;
1509
};
1510
 
1511
// ----------------------------------------------------------------------------
1512
// The CdlNode class (and hence just about everything) contains a
1513
// vector of CdlReferrer objects. This keeps track of all entities
1514
// that refer to this one, so if the value associated with this
1515
// changes it is possible to work out the impact of this on all
1516
// entities that rely on this value.
1517
//
1518
// Arguably this should work in terms of CdlValuable objects rather
1519
// than CdlNode objects. However it is convenient to use references
1520
// for the connection between e.g. an option and a dialog, where
1521
// there is no value involved. The reverse connection is of little
1522
// use in this circumstance.
1523
//
1524
// CdlReferrer objects are rarely accessed directly. Instead they will
1525
// be filled in during a CdlReference::bind() operation and erased
1526
// during a CdlReference::unbind() operation. The only operations that
1527
// should be public allow access to the contained data.
1528
 
1529
class CdlReferrer {
1530
 
1531
    friend class        CdlTest;
1532
 
1533
    // CdlReference::bind() and unbind() have direct access to the
1534
    // members, since these two functions are really responsible for
1535
    // creating and destroying referrer objects.
1536
    friend class        CdlReference;
1537
 
1538
  public:
1539
 
1540
    // The default constructor, copy constructor and assignment
1541
    // operator are all public to avoid problems with having vectors
1542
    // of referrer objects. Similarly the destructor is public.
1543
    // In practice updates actually happen as a consequence of
1544
    // CdlReference::bind() and CdlReference::unbind().
1545
    CdlReferrer();
1546
    CdlReferrer(const CdlReferrer&);
1547
    CdlReferrer& operator=(const CdlReferrer&);
1548
    ~CdlReferrer();
1549
 
1550
    CdlNode     get_source() const;
1551
    CdlProperty get_source_property() const;
1552
    void        update(CdlTransaction, CdlNode, CdlUpdate);
1553
    bool        check_this(cyg_assert_class_zeal=cyg_quick) const;
1554
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
1555
 
1556
  private:
1557
 
1558
    CdlNode     source;
1559
    CdlProperty source_property;
1560
 
1561
    enum {
1562
        CdlReferrer_Invalid = 0,
1563
        CdlReferrer_Magic   = 0x70e1fc37
1564
    } cdlreferrer_cookie;
1565
};
1566
 
1567
//}}}
1568
//{{{  Value and Expression  classes
1569
 
1570
//{{{  CdlEvalContext
1571
 
1572
// ----------------------------------------------------------------------------
1573
// Expression evaluation always happens within a certain context.
1574
// This may involve a transaction. Usually it involves a node and
1575
// a property within that node, although it is possible to evaluate
1576
// expressions from inside Tcl code.
1577
//
1578
// To avoid passing too many arguments around the various
1579
// evaluation-related routines, a utility class is provided.
1580
 
1581
class CdlEvalContext {
1582
 
1583
    friend class CdlTest;
1584
 
1585
  public:
1586
 
1587
    CdlTransaction      transaction;
1588
    CdlNode             node;
1589
    CdlProperty         property;
1590
    CdlToplevel         toplevel;
1591
 
1592
    CdlEvalContext(CdlTransaction, CdlNode = 0, CdlProperty = 0, CdlToplevel = 0);
1593
    ~CdlEvalContext();
1594
 
1595
    // Given a reference inside an expression, try to resolve this to either
1596
    // a node or, more specifically, a valuable.
1597
    CdlNode             resolve_reference(CdlExpression, int);
1598
    CdlValuable         resolve_valuable_reference(CdlExpression, int);
1599
 
1600
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
1601
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
1602
 
1603
  protected:
1604
 
1605
  private:
1606
    // Illegal operation, the three fields must always be supplied,
1607
    // although they may be zero.
1608
    CdlEvalContext();
1609
 
1610
    enum {
1611
        CdlEvalContext_Invalid  = 0,
1612
        CdlEvalContext_Magic    = 0x03434be9
1613
    } cdlevalcontext_cookie;
1614
 
1615
};
1616
 
1617
//}}}
1618
//{{{  CdlSimpleValue
1619
 
1620
// ----------------------------------------------------------------------------
1621
// Expression evaluation happens in terms of CdlSimpleValue objects.
1622
// In CDL all values are strings, but for the purposes of arithmetic
1623
// these strings sometimes have to be interpreted as integers or as
1624
// double precision numbers. Sometimes there is a choice, for example
1625
// the equality operator == can mean numerical or string comparison.
1626
// The basic rules that get applied are:
1627
//
1628
//    1) if the current value has an integer representation then
1629
//       use this by preference. This means that an expression
1630
//       of the form (CYGNUM_XXX != 0x100) will do a integer
1631
//       comparison if possible.
1632
//
1633
//    2) otherwise if the current value can be interpreted as a
1634
//       double precision number, use that representation.
1635
//       All integers can be interpreted as doubles (at the risk
1636
//       of some loss of precision), so the representation as
1637
//       a double should only be used if the integer representation
1638
//       is inappropriate.
1639
//
1640
//    3) otherwise interpret the value as a string.
1641
//
1642
// The default value is 0.
1643
 
1644
class CdlSimpleValue {
1645
 
1646
    friend class CdlTest;
1647
 
1648
  public:
1649
 
1650
    CdlSimpleValue();
1651
    CdlSimpleValue(std::string);
1652
    CdlSimpleValue(cdl_int);
1653
    CdlSimpleValue(double);
1654
    CdlSimpleValue(const CdlSimpleValue&);
1655
    CdlSimpleValue(bool);
1656
    ~CdlSimpleValue();
1657
 
1658
    CdlSimpleValue&     operator=(const CdlSimpleValue&);
1659
    CdlSimpleValue&     operator=(std::string);
1660
    CdlSimpleValue&     operator=(cdl_int);
1661
    CdlSimpleValue&     operator=(double);
1662
 
1663
    CdlSimpleValue&     operator=(bool);
1664
 
1665
    bool                operator==(const CdlSimpleValue&) const;
1666
    bool                operator!=(const CdlSimpleValue&) const;
1667
    bool                operator==(std::string arg) const
1668
    {
1669
        CdlSimpleValue val(arg);
1670
        return *this == val;
1671
    }
1672
    bool                operator==(cdl_int arg) const
1673
    {
1674
        CdlSimpleValue val(arg);
1675
        return *this == val;
1676
    }
1677
    bool                operator==(double arg) const
1678
    {
1679
        CdlSimpleValue val(arg);
1680
        return *this == val;
1681
    }
1682
    bool                operator!=(std::string arg) const
1683
    {
1684
        CdlSimpleValue val(arg);
1685
        return *this != val;
1686
    }
1687
    bool                operator!=(cdl_int arg) const
1688
    {
1689
        CdlSimpleValue val(arg);
1690
        return *this != val;
1691
    }
1692
    bool                operator!=(double arg) const
1693
    {
1694
        CdlSimpleValue val(arg);
1695
        return *this != val;
1696
    }
1697
 
1698
    void                set_value(std::string, CdlValueFormat = CdlValueFormat_Default);
1699
    std::string         get_value() const;
1700
 
1701
    bool                has_integer_value() const;
1702
    void                set_integer_value(cdl_int, CdlValueFormat = CdlValueFormat_Default);
1703
    cdl_int             get_integer_value() const;
1704
 
1705
    bool                has_double_value() const;
1706
    void                set_double_value(double, CdlValueFormat = CdlValueFormat_Default);
1707
    double              get_double_value() const;
1708
 
1709
    CdlValueFormat      get_value_format() const;
1710
    void                set_value_format(CdlValueFormat);
1711
    void                set_value_format(CdlSimpleValue&);
1712
    void                set_value_format(CdlSimpleValue&, CdlSimpleValue&);
1713
 
1714
    static void         eval_valuable(CdlEvalContext&, CdlValuable, CdlSimpleValue&);
1715
 
1716
    // For expression evaluation, it is often convenient to get hold
1717
    // of a boolean as well. This may indicate a non-empty string
1718
    // or a non-zero value.
1719
    bool                get_bool_value() const;
1720
 
1721
    // This class is too simple to warrant even a cookie validation.
1722
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const {
1723
        return true;
1724
    }
1725
 
1726
  protected:
1727
 
1728
  private:
1729
    enum {
1730
        int_valid       = 0x01,
1731
        double_valid    = 0x02,
1732
        string_valid    = 0x04,
1733
        int_invalid     = 0x08,
1734
        double_invalid  = 0x10
1735
    };
1736
    mutable int         valid_flags;
1737
    mutable std::string value;
1738
    mutable cdl_int     int_value;
1739
    mutable double      double_value;
1740
    CdlValueFormat      format;
1741
};
1742
 
1743
//}}}
1744
//{{{  CdlListValue
1745
 
1746
// ----------------------------------------------------------------------------
1747
// Evaluating a list expression results in a set of possible values, but
1748
// unlike the original list expression these values are now constant and
1749
// can have no dependencies on CDL entities. As with list expressions the
1750
// main operation on a list value is to detect membership, but using
1751
// list values allows multiple potential members to be tested without
1752
// repeated expression evaluation. The main use of list values is implicit
1753
// in libcdl, each list expression contains a mutable cached list value.
1754
//
1755
// A list value contains five sets of data:
1756
//
1757
// 1) separate vectors of strings, integers, and floating point constants.
1758
//    Having separate vectors of integers and floating points avoids
1759
//    problems when numbers can be represented in different formats.
1760
// 2) a vector of cdl_int pairs for ranges of integer data
1761
// 3) a vector of double pairs for ranges of floating point data
1762
//
1763
// Any of these vectors may be empty, but at least one of the vectors should
1764
// contain useful data. Possibly there should also be tables for cdl_int and
1765
// double to avoid unnecessary string conversions.
1766
 
1767
class CdlListValue {
1768
 
1769
    friend class        CdlTest;
1770
 
1771
    // A list value will only be filled in when a list expression is evaluated.
1772
    // The members cannot be updated by other means.
1773
    friend class        CdlListExpressionBody;
1774
 
1775
  public:
1776
 
1777
    CdlListValue();
1778
    ~CdlListValue();
1779
    CdlListValue(const CdlListValue&);
1780
    CdlListValue& operator=(const CdlListValue&);
1781
 
1782
    bool        is_member(CdlSimpleValue&) const;
1783
    bool        is_member(std::string, bool = true) const;
1784
    bool        is_member(cdl_int, bool = true) const;
1785
    bool        is_member(double, bool = true) const;
1786
 
1787
    // These provide access to the raw data, for example if it is
1788
    // necessary to suggest a legal value to the user.
1789
    const std::vector&                get_table() const;
1790
    const std::vector >&  get_integer_ranges() const;
1791
    const std::vector >&    get_double_ranges() const;
1792
 
1793
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
1794
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
1795
 
1796
  private:
1797
    std::vector                 table;
1798
    std::vector >   integer_ranges;
1799
    std::vector >     double_ranges;
1800
 
1801
    enum {
1802
        CdlListValue_Invalid  = 0,
1803
        CdlListValue_Magic    = 0x2183a943
1804
    } cdllistvalue_cookie;
1805
};
1806
 
1807
//}}}
1808
//{{{  CdlValue
1809
 
1810
// ----------------------------------------------------------------------------
1811
// Values in CDL are non-trivial compared with some other languages.
1812
// Even though CDL is not a fully-typed language, it does still have
1813
// four different flavors to consider. There is also the problem that
1814
// an entity may have up to four different values which should be
1815
// stored (default, inferred, wizard, user), with the ability to
1816
// switch between them. The CdlValue class provides support for this.
1817
//
1818
// CdlValue objects are not normally updated explicitly. Instead
1819
// higher level code deals with CdlValuable objects, which inherit
1820
// privately from CdlValue. Modifications to CdlValuables happen in
1821
// the context of a transaction.
1822
//
1823
// The first concept to take into account is the flavor. There
1824
// are four flavors, None, Bool, BoolData and Data. The member
1825
// function get_flavor() can be used to obtain the current flavor.
1826
//
1827
//     CdlValueFlavor CdlValue::get_flavor() const;
1828
//
1829
// Values may be enabled or disabled. Values of flavor None
1830
// and Data are always enabled. Values of flavor Bool or BoolData
1831
// may or may not be enabled, by default they are disabled.
1832
//
1833
//     bool CdlValue::is_enabled(...) const;
1834
//
1835
// (The optional argument to is_enabled() is discussed later).
1836
//
1837
// Values of flavor BoolData and Data also have a string value,
1838
// which can be interpreted as an integer or a double under
1839
// the right circumstances.
1840
//
1841
//     std::string CdlValue::get_value(...) const;
1842
//     bool        CdlValue::has_integer_value(...) const;
1843
//     bool        CdlValue::has_double_value(...) const;
1844
//     cdl_int     CdlValue::get_integer_value(...) const;
1845
//     double      CdlValue::get_double_value(...) const;
1846
//
1847
// This is equivalent to a CdlSimpleValue object, and in fact
1848
// that is the internal representation. It is possible to
1849
// get hold of the CdlSimpleValue object directly:
1850
//
1851
//     CdlSimpleValue CdlValue::get_simple_value(...) const;
1852
//
1853
// The get_integer_value() and get_double_value() members should
1854
// only be used if you are confident that the current value has
1855
// an integer or double representation. Otherwise the result is
1856
// undefined.
1857
//
1858
// The optional argument to these member functions represents
1859
// the source. A value can be set from four different sources:
1860
// the default value (usually either 0 or the result of
1861
// evaluating a default_value property); an inferred value,
1862
// determined by the inference engine; a wizard value, i.e.
1863
// what a CDL wizard believes the correct value to be based
1864
// on user input; and a user value, something explicitly
1865
// set by the end user. These have different priorities:
1866
// the inference engine can override default values but not
1867
// user values. A CdlValue object keeps track of the current
1868
// source.
1869
//
1870
//    CdlValueSource CdlValue::get_source() const;
1871
//
1872
// If no argument is given to e.g. is_enabled() then the
1873
// current source is used. Otherwise it is possible to find
1874
// out whether or not the entity is enabled for each of the
1875
// sources.
1876
//
1877
// The default source is always defined, the others may or
1878
// may not be. It is possible to find out for each source
1879
// whether or not a value has been set.
1880
//
1881
//   bool CdlValue::has_source(CdlValueSource) const;
1882
//
1883
//
1884
// Updating values normally happens in the CdlValuable class,
1885
// but the member functions are the same. There is a member
1886
// function to change the flavor:
1887
//
1888
//   void CdlValue::set_flavor(CdlValueFlavor);
1889
//
1890
// However this member function is intended only for use by the
1891
// library itself. An entity's flavor is normally defined by CDL data,
1892
// and should not be updated explicitly by application code.
1893
//
1894
// There are two member functions to manipulate the value source:
1895
//
1896
//     void CdlValue::set_source(CdlValueSource);
1897
//     void CdlValue::invalidate_source(CdlValueSource);
1898
//
1899
// The first function can be used if e.g. the user wants to
1900
// change his or her mind and go back to the default value
1901
// rather than a user value. The user value is not forgotten
1902
// and can be reinstated.
1903
//
1904
// invalidate_source() can be used to completely cancel a
1905
// value source. If that source happens to be the current one
1906
// then the current source will be adjusted appropriately.
1907
// It is illegal to attempt to invalidate the default source.
1908
//
1909
// For values with flavor Bool and BoolData, there are three
1910
// member functions that can be used to control the enabled
1911
// status:
1912
//
1913
//   void CdlValue::set_enabled(bool, CdlValueSource);
1914
//   void CdlValue::enable(CdlValueSource);
1915
//   void CdlValue::disable(CdlValueSource);
1916
//
1917
// Note that when updating a CdlValue object the source should
1918
// be known and must be specified. If the source has a higher
1919
// priority than the current one then it will automatically
1920
// become the new source. On the rare occasion that this is
1921
// not desired, set_source() will have to be used afterwards
1922
// to reset the current source.
1923
//
1924
// For values with flavor BoolData and Data the following
1925
// member functions are available to change the value string:
1926
//
1927
//   void CdlValue::set_value(std::string, CdlValueSource);
1928
//   void CdlValue::set_value(cdl_int, CdlValueSource);
1929
//   void CdlValue::set_value(double, CdlvalueSource);
1930
//   void CdlValue::set_value(CdlSimpleValue&, CdlValueSource);
1931
//
1932
// For values with flavor BoolData is is possible to
1933
// combine updating the enabled flag and the string value:
1934
//
1935
//   void CdlValue::set_enabled_and_value(bool, std::string, CdlValueSource);
1936
//   void CdlValue::set_enabled_and_value(bool, cdl_int, CdlValueSource);
1937
//   void CdlValue::set_enabled_and_value(bool, double, CdlValueSource);
1938
//   void CdlValue::set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
1939
//   void CdlValue::enable_and_set_value(std::string, CdlValueSource);
1940
//   void CdlValue::enable_and_set_value(cdl_int, CdlValueSource);
1941
//   void CdlValue::enable_and_set_value(double, CdlValueSource);
1942
//   void CdlValue::enable_and_set_value(CdlSimpleValue&, CdlValueSource);
1943
//   void CdlValue::disable_and_set_value(std::string, CdlValueSource);
1944
//   void CdlValue::disable_and_set_value(cdl_int, CdlValueSource);
1945
//   void CdlValue::disable_and_set_value(double, CdlValueSource);
1946
//   void CdlValue::disable_and_set_value(CdlSimpleValue&, CdlValueSource);
1947
//
1948
// Obviously many of these functions are just simple inlines.
1949
//
1950
// There is one final member function:
1951
//
1952
//   void CdlValue::set(CdlSimpleValue, CdlValueSource);
1953
//
1954
// This member function is defined to do the right thing,
1955
// whatever the flavor happens to be.
1956
 
1957
class CdlValue {
1958
 
1959
    friend class CdlTest;
1960
 
1961
  public:
1962
 
1963
    CdlValue(CdlValueFlavor = CdlValueFlavor_Bool);
1964
    virtual ~CdlValue();
1965
    CdlValue(const CdlValue&);
1966
    CdlValue&           operator=(const CdlValue&);
1967
 
1968
    CdlValueFlavor      get_flavor() const;
1969
    CdlValueSource      get_source() const;
1970
    bool                has_source(CdlValueSource) const;
1971
 
1972
    bool                is_enabled(CdlValueSource = CdlValueSource_Current) const;
1973
    std::string         get_value(CdlValueSource = CdlValueSource_Current) const;
1974
    bool                has_integer_value(CdlValueSource = CdlValueSource_Current) const;
1975
    bool                has_double_value(CdlValueSource = CdlValueSource_Current) const;
1976
    cdl_int             get_integer_value(CdlValueSource = CdlValueSource_Current) const;
1977
    double              get_double_value(CdlValueSource = CdlValueSource_Current) const;
1978
    CdlSimpleValue      get_simple_value(CdlValueSource = CdlValueSource_Current) const;
1979
 
1980
    void set_source(CdlValueSource);
1981
    void invalidate_source(CdlValueSource);
1982
 
1983
    void set_enabled(bool, CdlValueSource);
1984
    void enable(CdlValueSource source)
1985
    {
1986
        set_enabled(true, source);
1987
    }
1988
    void disable(CdlValueSource source)
1989
    {
1990
        set_enabled(false, source);
1991
    }
1992
 
1993
    void set_value(CdlSimpleValue&, CdlValueSource);
1994
    void set_value(std::string data, CdlValueSource source)
1995
    {
1996
        CdlSimpleValue val(data);
1997
        set_value(val, source);
1998
    }
1999
    void set_integer_value(cdl_int data, CdlValueSource source)
2000
    {
2001
        CdlSimpleValue val(data);
2002
        set_value(val, source);
2003
    }
2004
    void set_double_value(double data, CdlValueSource source)
2005
    {
2006
        CdlSimpleValue val(data);
2007
        set_value(val, source);
2008
    }
2009
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
2010
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
2011
    {
2012
        CdlSimpleValue val(data);
2013
        set_enabled_and_value(enabled, val, source);
2014
    }
2015
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
2016
    {
2017
        CdlSimpleValue val(data);
2018
        set_enabled_and_value(enabled, val, source);
2019
    }
2020
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
2021
    {
2022
        CdlSimpleValue val(data);
2023
        set_enabled_and_value(enabled, val, source);
2024
    }
2025
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2026
    {
2027
        set_enabled_and_value(true, val, source);
2028
    }
2029
    void enable_and_set_value(std::string data, CdlValueSource source)
2030
    {
2031
        set_enabled_and_value(true, data, source);
2032
    }
2033
    void enable_and_set_value(cdl_int data, CdlValueSource source)
2034
    {
2035
        set_enabled_and_value(true, data, source);
2036
    }
2037
    void enable_and_set_value(double data, CdlValueSource source)
2038
    {
2039
        set_enabled_and_value(true, data, source);
2040
    }
2041
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
2042
    {
2043
        set_enabled_and_value(false, val, source);
2044
    }
2045
    void disable_and_set_value(std::string data, CdlValueSource source)
2046
    {
2047
        set_enabled_and_value(false, data, source);
2048
    }
2049
    void disable_and_set_value(cdl_int data, CdlValueSource source)
2050
    {
2051
        set_enabled_and_value(false, data, source);
2052
    }
2053
    void disable_and_set_value(double data, CdlValueSource source)
2054
    {
2055
        set_enabled_and_value(false, data, source);
2056
    }
2057
 
2058
    void set(CdlSimpleValue&, CdlValueSource);
2059
 
2060
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2061
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2062
 
2063
    // This should only be used by the library itself.
2064
    void                set_flavor(CdlValueFlavor);
2065
 
2066
  protected:
2067
 
2068
  private:
2069
 
2070
    CdlValueFlavor      flavor;
2071
    CdlValueSource      current_source;
2072
 
2073
    // FIXME: a static const member should be used for the array
2074
    // sizes, but VC++ does not support that part of the language.
2075
    // FIXME: std::bitset should be used here. Using lots of separate
2076
    // bools here is inefficient.
2077
    bool                source_valid[4];
2078
    bool                enabled[4];
2079
    CdlSimpleValue      values[4];
2080
 
2081
    enum {
2082
        CdlValue_Invalid = 0,
2083
        CdlValue_Magic   = 0x41837960
2084
    } cdlvalue_cookie;
2085
};
2086
 
2087
//}}}
2088
//{{{  CdlSubexpression
2089
 
2090
// ----------------------------------------------------------------------------
2091
// Expressions come into existence primarily as the result of reading
2092
// in certain properties like default_value in CDL data. It is also
2093
// possible for expressions to be generated and evaluated on the fly
2094
// inside Tcl code, but that is expected to be a comparatively rare
2095
// events. Expression objects always live on the heap, usually only
2096
// in derived classes.
2097
//
2098
// An ordinary expression evaluates to a single value. There are two
2099
// other types of expression in the CDL language, goal expressions and
2100
// list expression. A goal expression is essentially a set of ordinary
2101
// expressions with implicit &&'s between them. A list expression
2102
// is a set of expressions that can be evaluated to a constant vector,
2103
// plus pairs of expressions that constitute ranges. Again goal and
2104
// list expressions only live on the heap.
2105
//
2106
// Both parsing an evaluation involve tokens for the various
2107
// operators. The inference engine, conflict reporting code, and
2108
// other diagnostic code will also need to have ready access to
2109
// this information. Hence it makes a bit more sense to have
2110
// the enum outside the expression class.
2111
 
2112
enum CdlExprOp {
2113
    CdlExprOp_Invalid           =  0,
2114
    CdlExprOp_EOD               =  1,   // End of data reached
2115
    CdlEXprOp_Command           =  2,   // [tcl code]
2116
    CdlExprOp_Variable          =  3,   // $tcl_variable
2117
    CdlExprOp_StringConstant    =  4,   // "hello"
2118
    CdlExprOp_IntegerConstant   =  5,   // 123
2119
    CdlExprOp_DoubleConstant    =  6,   // 3.1415
2120
    CdlExprOp_Reference         =  7,   // CYGPKG_INFRA
2121
    CdlExprOp_Range             =  8,   // x to y
2122
    CdlExprOp_Negate            =  9,   // -x
2123
    CdlExprOp_Plus              = 10,   // +x
2124
    CdlExprOp_LogicalNot        = 11,   // !x
2125
    CdlExprOp_BitNot            = 12,   // ~x
2126
    CdlExprOp_Indirect          = 13,   // *x
2127
    CdlExprOp_Active            = 14,   // ?x
2128
    CdlExprOp_Function          = 15,   // sin(x)
2129
    CdlExprOp_Multiply          = 16,   // x * y
2130
    CdlExprOp_Divide            = 17,   // x / y
2131
    CdlExprOp_Remainder         = 18,   // x % y
2132
    CdlExprOp_Add               = 19,   // x + y
2133
    CdlExprOp_Subtract          = 20,   // x - y
2134
    CdlExprOp_LeftShift         = 21,   // x << y
2135
    CdlExprOp_RightShift        = 22,   // x >> y
2136
    CdlExprOp_LessThan          = 23,   // x < y
2137
    CdlExprOp_LessEqual         = 24,   // x <= y
2138
    CdlExprOp_GreaterThan       = 25,   // x > y
2139
    CdlExprOp_GreaterEqual      = 26,   // x >= y
2140
    CdlExprOp_Equal             = 27,   // x == y
2141
    CdlExprOp_NotEqual          = 28,   // x != y
2142
    CdlExprOp_BitAnd            = 29,   // x & y
2143
    CdlExprOp_BitXor            = 30,   // x ^ y
2144
    CdlExprOp_BitOr             = 31,   // x | y
2145
    CdlExprOp_And               = 32,   // x && y
2146
    CdlExprOp_Or                = 33,   // x || y
2147
    CdlExprOp_Cond              = 34,   // x ? a : b
2148
    CdlExprOp_StringConcat      = 35,   // x . y
2149
    CdlExprOp_Implies           = 36,   // x implies y
2150
    CdlExprOp_Xor               = 37,   // x xor y
2151
    CdlExprOp_Eqv               = 38    // x eqv y
2152
};
2153
 
2154
// ----------------------------------------------------------------------------
2155
// A subexpression consists of an operation, possibly some constant
2156
// data, and possibly indices into the subexpression vector.
2157
// Normally some unions would be used, but unions and objects such
2158
// as std::string do not mix, and the amount of memory involved is
2159
// not big enough to really worry about.
2160
 
2161
#define CdlFunction_MaxArgs     3
2162
struct CdlSubexpression {
2163
 
2164
    CdlExprOp           op;
2165
    CdlSimpleValue      constants;              // String, integer or double constant
2166
    int                 reference_index;        // iff CdlExprOp_Reference
2167
 
2168
    int                 lhs_index;              // for all non-constant operators
2169
    int                 rhs_index;              // for binary and ternary operators only
2170
    int                 rrhs_index;             // only for ternary operators.
2171
 
2172
    int                 func;                   // iff CdlExprOp_Function
2173
    int                 args[CdlFunction_MaxArgs];
2174
};
2175
 
2176
//}}}
2177
//{{{  CdlFunction
2178
 
2179
// ----------------------------------------------------------------------------
2180
// Generic support for function parsing, evaluation, and inference. The
2181
// implementation is extensible so that functions can be added to the
2182
// core via static constructors.
2183
 
2184
class CdlFunction {
2185
 
2186
    friend class CdlTest;
2187
 
2188
  public:
2189
    CdlFunction(const char* /* name */, int /* no_args */,
2190
                void (*)(CdlExpression, const CdlSubexpression&),
2191
                void (*)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
2192
                bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int),
2193
                bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)
2194
                );
2195
    ~CdlFunction();
2196
 
2197
    static bool         is_function(std::string, int&);
2198
    static std::string  get_name(int);
2199
    static int          get_args_count(int);
2200
 
2201
    static void         check(CdlExpression, const CdlSubexpression&);
2202
    static void         eval(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
2203
    static bool         infer_bool(CdlTransaction, CdlExpression, unsigned int, bool, int);
2204
    static bool         infer_value(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2205
 
2206
    static void         (*null_check)(CdlExpression, const CdlSubexpression&);
2207
    static bool         (*null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int);
2208
    static bool         (*null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2209
 
2210
  protected:
2211
 
2212
  private:
2213
    // Keep track of all functions in the system
2214
    static std::vector    all_functions;
2215
 
2216
    // Each function object is given a unique id during initialization
2217
    static int          next_id;
2218
    int                 id;
2219
 
2220
    // Provided by the constructor
2221
    const char*         name;
2222
    int                 number_args;
2223
    void                (*check_fn)(CdlExpression, const CdlSubexpression&);
2224
    void                (*eval_fn)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&);
2225
    bool                (*infer_bool_fn)(CdlTransaction, CdlExpression, unsigned int, bool, int);
2226
    bool                (*infer_value_fn)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int);
2227
 
2228
    // The default constructor is illegal
2229
    CdlFunction();
2230
};
2231
 
2232
//}}}
2233
//{{{  CdlExpression
2234
 
2235
// ----------------------------------------------------------------------------
2236
// And now for the expression class itself.
2237
 
2238
class CdlExpressionBody {
2239
 
2240
    friend class CdlTest;
2241
 
2242
  public:
2243
 
2244
    // The default constructor is basically a no-op, new expression
2245
    // objects only get created as a consequence of parsing. However
2246
    // it exists and is protected for the convenience of derived
2247
    // classes. The copy constructor is protected, allowing parsing
2248
    // code to first parse an expression and then copy the expression
2249
    // into a higher level object. The assignment operator is illegal.
2250
    // There is no reason to hide the destructor.
2251
    virtual ~CdlExpressionBody();
2252
 
2253
    // An expression involves three pieces of data. There is a vector
2254
    // of subexpressions. It is also necessary to know where
2255
    // evaluation should being, in accordance with operator precedence
2256
    // rules. And there is a vector of CdlReference objects - this
2257
    // needs to be kept separate from the subexpression vector because
2258
    // CdlReference objects are comparatively tricky.
2259
    //
2260
    // All of this data is public and can be readily inspected by the
2261
    // inference engine, by conflict detection code, by diagnostic
2262
    // code, etc.
2263
    std::vector       sub_expressions;
2264
    int                                 first_subexpression;
2265
    std::vector           references;
2266
    bool                                update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2267
 
2268
    // There are a number of parsing functions. The first one is
2269
    // used by higher-level code to parse a single expression. Its
2270
    // argument is a single string (which may be the result of
2271
    // concatenating several Tcl arguments), and at the end of the
2272
    // parse operation there should be no further data. The result
2273
    // will either be a new expression object or a parsing exception
2274
    // to be caught by higher level code.
2275
    static CdlExpression        parse(std::string);
2276
 
2277
    // This is used when parsing list expressions, which involve a
2278
    // sequence of ordinary expressions and possibly range operators.
2279
    // The whole list expression lives in a single string, and it is
2280
    // necessary to provide an index indicating where in the string
2281
    // parsing should begin. It is also useful to return details of
2282
    // the token that caused parsing to terminate (EOD, Range, or
2283
    // the start of something else).
2284
    static CdlExpression        parse(std::string, int&, CdlExprOp&, int&);
2285
 
2286
    // A goal expression is derived from an ordinary expression but
2287
    // has somewhat different rules for evaluating. Parsing a goal
2288
    // expression involves parsing a number of ordinary expressions
2289
    // with implicit && operators between them, and it requires
2290
    // a parsing function that can be used to extend an existing
2291
    // expression.
2292
    //
2293
    // NOTE: possibly this should should be a protected member, since
2294
    // its main use is in parsing goal expressions.
2295
    static void continue_parse(CdlExpression, std::string, int&, CdlExprOp&, int&);
2296
 
2297
    // Evaluating expressions. Note that this may fail at run-time
2298
    // because of errors that cannot be caught sensibly when the
2299
    // expression is read in, for example arithmetic overflow or
2300
    // division by zero. Because such failures are a possibility
2301
    // anyway no special action is taken to prevent an expression
2302
    // with e.g. an unresolved reference from being evaluated.
2303
    //
2304
    // eval() is the public interface, and manages
2305
    // CdlConflict_EvalException objects. eval_internal() is for use
2306
    // by list and goal expressions.
2307
    void eval(CdlEvalContext&, CdlSimpleValue&);
2308
    void eval_internal(CdlEvalContext&, CdlSimpleValue&);
2309
    void eval_subexpression(CdlEvalContext&, int, CdlSimpleValue&);
2310
 
2311
    // The full original expression is useful for diagnostics purposes
2312
    std::string get_original_string() const;
2313
 
2314
    bool        check_this(cyg_assert_class_zeal cyg_quick) const;
2315
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2316
 
2317
  protected:
2318
 
2319
    // The default constructor does very little, the main work
2320
    // is done by the various parsing functions. However it is
2321
    // available to derived classes, especially goal expressions.
2322
    CdlExpressionBody();
2323
 
2324
    // The copy constructor has to be usable by derived classes,
2325
    // e.g. CdlExpressionProperty
2326
    CdlExpressionBody(const CdlExpressionBody&);
2327
 
2328
  private:
2329
 
2330
 
2331
    // The assignment operator is illegal.
2332
    CdlExpressionBody&  operator=(const CdlExpressionBody&);
2333
 
2334
    // The string that was parsed originally
2335
    std::string                 expression_string;
2336
 
2337
    enum {
2338
        CdlExpressionBody_Invalid       = 0,
2339
        CdlExpressionBody_Magic         = 0x760293a3
2340
    } cdlexpressionbody_cookie;
2341
};
2342
 
2343
//}}}
2344
//{{{  CdlListExpression
2345
 
2346
// ----------------------------------------------------------------------------
2347
// The main use of list expressions is for the legal_values
2348
// properties. Essentially a list expression is just a vector of
2349
// ordinary expressions and ranges of expressions.
2350
 
2351
class CdlListExpressionBody {
2352
 
2353
    friend class CdlTest;
2354
 
2355
  public:
2356
 
2357
    // Availability of constructors etc. is as per the ordinary
2358
    // expression class.
2359
    virtual ~CdlListExpressionBody();
2360
 
2361
    // The data associated with a list expression is a vector of
2362
    // expressions, plus a vector of expression pairs constituting
2363
    // ranges. As with ordinary expressions the data is fully public
2364
    // and can be readily examined by e.g. the inference engine.
2365
    std::vector                                  data;
2366
    std::vector >        ranges;
2367
 
2368
    // Parsing. This involves taking a single string, typically from
2369
    // a CDL script, and parsing one or more ordinary expressions.
2370
    static CdlListExpression parse(std::string);
2371
 
2372
    // Evaluation support. A list expression evaluates to a list value.
2373
    void eval(CdlEvalContext&, CdlListValue&);
2374
 
2375
    // More commonly client code is going to be interested in whether
2376
    // or not a particular value is a legal member. The result
2377
    // cache ensures that it is possible to
2378
    bool is_member(CdlEvalContext&, CdlSimpleValue&);
2379
    bool is_member(CdlEvalContext&, std::string);
2380
    bool is_member(CdlEvalContext&, cdl_int);
2381
    bool is_member(CdlEvalContext&, double);
2382
 
2383
    // The full original expression is useful for diagnostics purposes
2384
    std::string get_original_string() const;
2385
 
2386
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2387
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2388
 
2389
  protected:
2390
    CdlListExpressionBody(const CdlListExpressionBody&);
2391
    bool        update(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
2392
 
2393
  private:
2394
 
2395
    CdlListExpressionBody();
2396
    CdlListExpressionBody& operator=(const CdlListExpressionBody&);
2397
 
2398
    void eval_internal(CdlEvalContext&, CdlListValue&);
2399
    std::string         expression_string;
2400
 
2401
    enum {
2402
        CdlListExpressionBody_Invalid   = 0,
2403
        CdlListExpressionBody_Magic     = 0x7da4bcc2
2404
    } cdllistexpressionbody_cookie;
2405
};
2406
 
2407
//}}}
2408
//{{{  CdlGoalExpression
2409
 
2410
// ----------------------------------------------------------------------------
2411
// A goal expression inherits privately from ordinary expressions. Essentially
2412
// a goal expression is simply a set of ordinary expressions separated by &&,
2413
// but it can only be evaluated to a boolean. The parse() and eval() members
2414
// of the base class should not be exposed. There is a member to get hold of
2415
// the underlying ordinary expression, for use by e.g. the inference engine.
2416
 
2417
class CdlGoalExpressionBody : private CdlExpressionBody {
2418
 
2419
    friend class CdlTest;
2420
 
2421
    typedef CdlExpressionBody inherited;
2422
 
2423
  public:
2424
    virtual ~CdlGoalExpressionBody();
2425
 
2426
    static CdlGoalExpression parse(std::string);
2427
 
2428
    // A few variants of the eval() member, with a choice of returning
2429
    // by value or by reference. The latter provide consistency with the
2430
    // other expression classes.
2431
    bool eval(CdlEvalContext&);
2432
    void eval(CdlEvalContext&, bool&);
2433
 
2434
    // Provide public access to the underlying expression object,
2435
    // useful for the inference engine
2436
    CdlExpression               get_expression();
2437
 
2438
    // The full original expression is useful for diagnostics purposes
2439
    std::string get_original_string() const;
2440
 
2441
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2442
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2443
 
2444
  protected:
2445
    CdlGoalExpressionBody(const CdlGoalExpressionBody&);
2446
 
2447
 
2448
  private:
2449
 
2450
    CdlGoalExpressionBody();
2451
    CdlGoalExpressionBody& operator=(const CdlGoalExpressionBody&);
2452
    void eval_internal(CdlEvalContext&, bool&);
2453
 
2454
    std::string expression_string;
2455
 
2456
    enum {
2457
        CdlGoalExpressionBody_Invalid = 0,
2458
        CdlGoalExpressionBody_Magic   = 0x5a58bb24
2459
    } cdlgoalexpressionbody_cookie;
2460
};
2461
 
2462
//}}}
2463
//{{{  CdlInfer
2464
 
2465
// ----------------------------------------------------------------------------
2466
// A utility class related to inference. This exports the main functions
2467
// needed, allowing e.g. per-function inference routines from func.cxx to
2468
// interact with the main inference engine.
2469
 
2470
class CdlInfer {
2471
  public:
2472
    static bool make_active(CdlTransaction, CdlNode, int /* level */);
2473
    static bool make_inactive(CdlTransaction, CdlNode, int /* level */);
2474
    static bool set_valuable_value(CdlTransaction, CdlValuable, CdlSimpleValue&, int /* level */);
2475
    static bool set_valuable_bool(CdlTransaction, CdlValuable, bool, int /* level */);
2476
    static bool subexpr_value(CdlTransaction, CdlExpression, unsigned int /* index */, CdlSimpleValue& goal, int /* level */);
2477
    static bool subexpr_bool(CdlTransaction, CdlExpression, unsigned int /* index */, bool, int /* level */);
2478
 
2479
  private:
2480
    CdlInfer();
2481
};
2482
 
2483
//}}}
2484
 
2485
//}}}
2486
//{{{  CdlConflict classes
2487
 
2488
// ----------------------------------------------------------------------------
2489
// As a configuration is created and modified there will be times when
2490
// things are not completely consistent. There may be a reference to
2491
// some option that is not in any package in the current
2492
// configuration. An option may have an invalid value, possibly as a
2493
// side effect of a change to some other option. There may be a
2494
// dependency that is not satisfied. There may be other types of
2495
// conflict.
2496
//
2497
// The library provides a base class CdlConflict, and a number of
2498
// derived classes for common types of conflict such as unresolved
2499
// references. All conflicts are associated with a CdlNode and a
2500
// property within that. It is possible to use dynamic_cast<> to find
2501
// out the exact type of a conflict, or alternatively to use the
2502
// virtual member function get_explanation().
2503
//
2504
// Conflicts may be disabled by the user if they are not actually
2505
// important as far as application code is concerned. In other words
2506
// the end user is allowed to override the constraints specified in
2507
// the CDL. This information is saved with the configuration data.
2508
// Preferably the user should give an explanation for why the conflict
2509
// is disabled, to serve as a reminder some months later when the
2510
// configuration is reloaded.
2511
//
2512
//
2513
// Conflicts have a fairly complicated life cycle. First it is
2514
// necessary to distinguish between structural and normal conflicts. A
2515
// structural conflict is typically caused by a reference to a
2516
// non-existent valuable. These conflicts are generally created only
2517
// when something is loaded, and only go away when something is
2518
// unloaded. A normal conflict is typically related to a value, for
2519
// example a value outside the legal range, or a "requires" property
2520
// that is not satisfied.
2521
//
2522
// Conflicts are created and destroyed in the context of a
2523
// transaction, which in turn operates in the context of a toplevel.
2524
// If the transaction is committed then new conflicts get added to the
2525
// appropriate toplevel list, and destroyed conflicts get removed from
2526
// the toplevel list. The transaction field indicates whether the
2527
// conflict is currently per-transaction or global.
2528
//
2529
// Transactions may get nested, i.e. a conflict may get created as
2530
// part of a sub-transaction, and when that sub-transaction is committed
2531
// the conflict is moved to the parent transaction.
2532
//
2533
// For each toplevel, libcdl keeps track of all conflicts. This only
2534
// applies to committed conflicts, per-transaction conflicts are not
2535
// accessible in this way.
2536
//
2537
// As part of a transaction, libcdl may attempt to find solutions for
2538
// particular conflicts, and those solutions may get installed
2539
// automatically. No attempt is made to keep track of solutions
2540
// on a global basis, only on a per-transaction basis.
2541
 
2542
class CdlConflictBody {
2543
 
2544
    friend class CdlTest;
2545
 
2546
    // Transactions and conflicts are closely connected
2547
    friend class CdlTransactionBody;
2548
 
2549
  public:
2550
 
2551
    // Creation happens only inside a derived class.
2552
    // Clearing a conflict only happens inside transactions.
2553
    // Destroying a conflict only happens from inside a
2554
    // per-transaction clear(), or during a transaction commit.
2555
 
2556
    // Is this conflict part of a transaction, or has it been committed to the toplevel.
2557
    CdlTransaction      get_transaction() const;
2558
 
2559
    // Is inference implemented for this type of conflict?
2560
    virtual bool        resolution_implemented() const;
2561
 
2562
    // Try to resolve an existing global conflict. A new transaction
2563
    // is created for this operation, the conflict is resolved within
2564
    // that transaction, and then CdlTransaction::body() is used to
2565
    // handle inference callbacks, commits, etc. See also
2566
    // CdlToplevel::resolve_conflicts() and
2567
    // CdlToplevel::resolve_all_conflicts(). The conflict may cease to
2568
    // exist as a side-effect of this call.
2569
    void                resolve();
2570
 
2571
    // Keep track of whether or not this conflict has a solution
2572
    // 1) a conflict may have a current solution. This gets invalidated
2573
    //    whenever there is a change to a value that was referenced
2574
    //    while identifying the solution.
2575
    //
2576
    //    A current solution is indicated by a non-empty solution vector.
2577
    //
2578
    // 2) a conflict may not have a current solution. Again this gets
2579
    //    invalidated whenever a referred value changes. There is a boolean
2580
    //    to keep track of this.
2581
    //
2582
    // 3) a conflict may not have a current solution, but another run of
2583
    //    the inference engine may find one.
2584
    bool                has_known_solution() const;
2585
    bool                has_no_solution() const;
2586
    const std::vector >& get_solution() const;
2587
    const std::set& get_solution_references() const;
2588
    void                clear_solution();
2589
 
2590
    // Provide a text message "explaining" the conflict.
2591
    // This only makes sense for derived classes.
2592
    virtual std::string get_explanation() const = 0;
2593
 
2594
    // Basic information access.
2595
    CdlNode             get_node() const;
2596
    CdlProperty         get_property() const;
2597
    bool                is_structural() const;
2598
 
2599
    // Enabling and disabling conflicts currently happens outside the
2600
    // context of any transaction.
2601
    // FIXME: these are not currently implemented. It would be necessary
2602
    // to store the information in the savefile, which requires an
2603
    // unambiguous way of identifying a conflict that is likely to
2604
    // survice package version changes.
2605
    void                disable(std::string);
2606
    void                enable();
2607
    bool                is_enabled() const;
2608
    std::string         get_disabled_reason() const;
2609
 
2610
    bool check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
2611
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2612
 
2613
  protected:
2614
    CdlConflictBody(CdlTransaction, CdlNode, CdlProperty, bool /* structural */);
2615
 
2616
    // The destructor gets accessed from inside the friend transaction class,
2617
    // either during a clear_conflict() or during a transaction commit.
2618
    virtual ~CdlConflictBody();
2619
 
2620
    // All conflicts are associated with a node and a property.
2621
    // This information will be useful to derived classes'
2622
    // implementations of get_explanation()
2623
    CdlNode             node;
2624
    CdlProperty         property;
2625
 
2626
  private:
2627
 
2628
    // Attempt to resolve a conflict in a sub-transaction
2629
    // This is invoked from inside the transaction resolve code.
2630
    // There are additional exported interfaces inside and outside
2631
    // the transaction class.
2632
    virtual bool        inner_resolve(CdlTransaction, int);
2633
 
2634
    // Keep track of the transaction in which this conflict was created.
2635
    // The field is cleared at the end of a transaction.
2636
    CdlTransaction      transaction;
2637
 
2638
    // Usually the derived class will decide whether or not
2639
    // this conflict is structural in nature, but the data
2640
    // needs to be available at base constructor time so
2641
    // a virtual function is not appropriate.
2642
    bool                structural;
2643
 
2644
    // Solution support
2645
    bool                                           no_solution;
2646
    std::vector > solution;
2647
    std::set                          solution_references;
2648
    void update_solution_validity(CdlValuable);
2649
 
2650
    // Users may disable a conflict. Usually they will have to
2651
    // supply a reason for this.
2652
    bool                enabled;
2653
    std::string         reason;
2654
 
2655
    enum {
2656
        CdlConflictBody_Invalid = 0,
2657
        CdlConflictBody_Magic   = 0x073e8853
2658
    } cdlconflictbody_cookie;
2659
 
2660
    // Illegal operations. Conflicts always live on the heap.
2661
    CdlConflictBody();
2662
    CdlConflictBody(const CdlConflictBody&);
2663
    CdlConflictBody& operator=(const CdlConflictBody&);
2664
};
2665
 
2666
// ----------------------------------------------------------------------------
2667
// An unresolved conflict means that there is a reference in some
2668
// property to an entity that is not yet in the current configuration.
2669
// The class provides convenient access to the name of the unresolved
2670
// entity.
2671
 
2672
class CdlConflict_UnresolvedBody : public CdlConflictBody {
2673
 
2674
    friend class CdlTest;
2675
  public:
2676
 
2677
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2678
 
2679
    std::string         get_target_name() const;
2680
    std::string         get_explanation() const;
2681
    static bool         test(CdlConflict);
2682
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2683
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2684
 
2685
  protected:
2686
 
2687
  private:
2688
    virtual ~CdlConflict_UnresolvedBody();
2689
    CdlConflict_UnresolvedBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2690
    std::string         target_name;
2691
    enum {
2692
        CdlConflict_UnresolvedBody_Invalid      = 0,
2693
        CdlConflict_UnresolvedBody_Magic        = 0x1b24bb8a
2694
    } cdlconflict_unresolvedbody_cookie;
2695
 
2696
    CdlConflict_UnresolvedBody();
2697
    CdlConflict_UnresolvedBody(const CdlConflict_UnresolvedBody&);
2698
    CdlConflict_UnresolvedBody& operator=(const CdlConflict_UnresolvedBody&);
2699
};
2700
 
2701
// ----------------------------------------------------------------------------
2702
// An illegal value can be caused because of a number of properties:
2703
// legal_values, check_proc, entry_proc, ... In the case of the latter
2704
// the Tcl code should provide text explaining why the value is
2705
// illegal.
2706
 
2707
class CdlConflict_IllegalValueBody : public CdlConflictBody {
2708
 
2709
    friend class CdlTest;
2710
 
2711
  public:
2712
 
2713
    static void         make(CdlTransaction, CdlNode, CdlProperty);
2714
 
2715
    bool                resolution_implemented() const;
2716
 
2717
    std::string         get_explanation() const;
2718
    void                set_explanation(std::string);
2719
    static bool         test(CdlConflict);
2720
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2721
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2722
 
2723
  protected:
2724
 
2725
  private:
2726
    virtual ~CdlConflict_IllegalValueBody();
2727
    bool    inner_resolve(CdlTransaction, int);
2728
    CdlConflict_IllegalValueBody(CdlTransaction, CdlNode, CdlProperty);
2729
    std::string explanation;
2730
    enum {
2731
        CdlConflict_IllegalValueBody_Invalid    = 0,
2732
        CdlConflict_IllegalValueBody_Magic      = 0x4fb27ed1
2733
    } cdlconflict_illegalvaluebody_cookie;
2734
 
2735
    CdlConflict_IllegalValueBody();
2736
    CdlConflict_IllegalValueBody(const CdlConflict_IllegalValueBody&);
2737
    CdlConflict_IllegalValueBody& operator=(const CdlConflict_IllegalValueBody&);
2738
};
2739
 
2740
// ----------------------------------------------------------------------------
2741
// There are times when expression evaluation will fail, e.g. because of
2742
// a division by zero. The explanation is supplied by the evaluation code.
2743
 
2744
class CdlConflict_EvalExceptionBody : public CdlConflictBody {
2745
 
2746
    friend class CdlTest;
2747
 
2748
  public:
2749
 
2750
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2751
 
2752
    std::string         get_explanation() const;
2753
    void                set_explanation(std::string);   // mainly for internal use
2754
    static bool         test(CdlConflict);
2755
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2756
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2757
 
2758
  protected:
2759
 
2760
  private:
2761
    virtual ~CdlConflict_EvalExceptionBody();
2762
    CdlConflict_EvalExceptionBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2763
    std::string explanation;
2764
    enum {
2765
        CdlConflict_EvalExceptionBody_Invalid   = 0,
2766
        CdlConflict_EvalExceptionBody_Magic     = 0x7e64bc41
2767
    } cdlconflict_evalexceptionbody_cookie;
2768
};
2769
 
2770
// ----------------------------------------------------------------------------
2771
// A goal expression evaluates to false. Producing sensible diagnostics
2772
// depends on a detailed understanding of goal expressions, which will
2773
// have to wait until the inference engine comes along.
2774
 
2775
class CdlConflict_RequiresBody : public CdlConflictBody {
2776
 
2777
    friend class CdlTest;
2778
 
2779
  public:
2780
 
2781
    static void         make(CdlTransaction, CdlNode, CdlProperty);
2782
    bool                resolution_implemented() const;
2783
 
2784
    std::string         get_explanation() const;
2785
    static bool         test(CdlConflict);
2786
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2787
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2788
 
2789
  protected:
2790
 
2791
  private:
2792
    virtual ~CdlConflict_RequiresBody();
2793
    bool     inner_resolve(CdlTransaction, int);
2794
    CdlConflict_RequiresBody(CdlTransaction, CdlNode, CdlProperty);
2795
    enum {
2796
        CdlConflict_RequiresBody_Invalid        = 0,
2797
        CdlConflict_RequiresBody_Magic          = 0x78436331
2798
    } cdlconflict_requiresbody_cookie;
2799
};
2800
 
2801
// ----------------------------------------------------------------------------
2802
// There is an unusual problem in the configuration data somewhere.
2803
// For example, a parent property can be resolved but the target is
2804
// not a container. There is not a lot that the user can do about
2805
// problems like this, apart from complaining to the component vendor,
2806
// but the problem should not be ignored either.
2807
 
2808
class CdlConflict_DataBody : public CdlConflictBody {
2809
 
2810
    friend class CdlTest;
2811
 
2812
  public:
2813
 
2814
    static void         make(CdlTransaction, CdlNode, CdlProperty, std::string);
2815
 
2816
    std::string         get_explanation() const;
2817
    static bool         test(CdlConflict);
2818
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
2819
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2820
 
2821
  protected:
2822
 
2823
  private:
2824
    virtual ~CdlConflict_DataBody();
2825
    CdlConflict_DataBody(CdlTransaction, CdlNode, CdlProperty, std::string);
2826
    std::string message;
2827
    enum {
2828
        CdlConflict_DataBody_Invalid    = 0,
2829
        CdlConflict_DataBody_Magic      = 0x2cec7ad8
2830
    } cdlconflict_databody_cookie;
2831
};
2832
 
2833
//}}}
2834
//{{{  CdlProperty class and derived classes
2835
 
2836
//{{{  Description
2837
 
2838
// ---------------------------------------------------------------------------
2839
// There are many different kinds of property. An alias property contains
2840
// a simple string. A check_proc property contains a fragment of Tcl code
2841
// which can be represented internally as a string, as bytecodes, or both.
2842
// A requires property contains a goal expression. ...
2843
//
2844
// The implementation involves a base class CdlProperty and various
2845
// derived classes such as CdlProperty_StringBody and
2846
// CdlProperty_ExpressionBody.
2847
//
2848
// New CdlProperty objects get created only when reading in CDL scripts,
2849
// while executing commands like alias and requires. These commands are
2850
// implemented as C++ functions hooked into the TCL interpreter. The
2851
// property arguments are available as an argc/argv pair. Each command
2852
// will parse and validate the arguments and then invoke an appropriate
2853
// constructor.
2854
 
2855
//}}}
2856
//{{{  CdlPropertyId_xxx
2857
 
2858
// ----------------------------------------------------------------------------
2859
// Properties are identified by strings rather than by an enum or anything
2860
// like that. A string-based approach allows new properties to be added at
2861
// any time without invalidating an existing enum, complicating switch()
2862
// statements, etc. There are some performance issues but these are
2863
// manageable.
2864
//
2865
// A disadvantage of using strings is that there is a problem with
2866
// typos. Mistyping something like CdlPropertyId_Compile will generally
2867
// result in a compile-time failure. Mistyping "Complie" will cause
2868
// strange behaviour at run-time and is hard to track down.
2869
//
2870
// A compromise solution is to have #define'd string constants.
2871
 
2872
#define CdlPropertyId_ActiveIf          "ActiveIf"
2873
#define CdlPropertyId_BuildProc         "BuildProc"
2874
#define CdlPropertyId_Calculated        "Calculated"
2875
#define CdlPropertyId_CancelProc        "CancelProc"
2876
#define CdlPropertyId_CheckProc         "CheckProc"
2877
#define CdlPropertyId_Compile           "Compile"
2878
#define CdlPropertyId_ConfirmProc       "ConfirmProc"
2879
#define CdlPropertyId_DecorationProc    "DecorationProc"
2880
#define CdlPropertyId_DefaultValue      "DefaultValue"
2881
#define CdlPropertyId_Define            "Define"
2882
#define CdlPropertyId_DefineHeader      "DefineHeader"
2883
#define CdlPropertyId_DefineProc        "DefineProc"
2884
#define CdlPropertyId_Description       "Description"
2885
#define CdlPropertyId_Dialog            "Dialog"
2886
#define CdlPropertyId_Display           "Display"
2887
#define CdlPropertyId_DisplayProc       "DisplayProc"
2888
#define CdlPropertyId_Doc               "Doc"
2889
#define CdlPropertyId_EntryProc         "EntryProc"
2890
#define CdlPropertyId_Flavor            "Flavor"
2891
#define CdlPropertyId_DefineFormat      "DefineFormat"
2892
#define CdlPropertyId_Group             "Group"
2893
#define CdlPropertyId_Hardware          "Hardware"
2894
#define CdlPropertyId_IfDefine          "IfDefine"
2895
#define CdlPropertyId_Implements        "Implements"
2896
#define CdlPropertyId_IncludeDir        "IncludeDir"
2897
#define CdlPropertyId_IncludeFiles      "IncludeFiles"
2898
#define CdlPropertyId_InitProc          "InitProc"
2899
#define CdlPropertyId_InstallProc       "InstallProc"
2900
#define CdlPropertyId_LegalValues       "LegalValues"
2901
#define CdlPropertyId_Library           "Library"
2902
#define CdlPropertyId_LicenseProc       "LicenseProc"
2903
#define CdlPropertyId_Make              "Make"
2904
#define CdlPropertyId_Makefile          "Makefile"
2905
#define CdlPropertyId_MakeObject        "MakeObject"
2906
#define CdlPropertyId_NoDefine          "NoDefine"
2907
#define CdlPropertyId_Object            "Object"
2908
#define CdlPropertyId_Parent            "Parent"
2909
#define CdlPropertyId_Requires          "Requires"
2910
#define CdlPropertyId_Screen            "Screen"
2911
#define CdlPropertyId_Script            "Script"
2912
#define CdlPropertyId_UpdateProc        "UpdateProc"
2913
#define CdlPropertyId_Wizard            "Wizard"
2914
 
2915
//}}}
2916
//{{{  Base class
2917
 
2918
// ----------------------------------------------------------------------------
2919
// The base class is never used directly. Instead the appropriate derived
2920
// objects are instantiated and when appropriate it will be necessary to
2921
// do a dynamic cast from a CdlProperty to e.g. a CdlProperty_String.
2922
 
2923
class CdlPropertyBody {
2924
 
2925
    friend class CdlTest;
2926
 
2927
  public:
2928
    // The destructor is public, to avoid possible problems with STL.
2929
    virtual ~CdlPropertyBody();
2930
 
2931
    // These routines provide access to the basic data.
2932
    std::string get_property_name() const;
2933
 
2934
    // Get hold of the arguments that were present in the original data.
2935
    int         get_argc() const;
2936
    bool        has_option(std::string) const;
2937
    std::string get_option(std::string) const;
2938
    const std::vector&     get_argv() const;
2939
    const std::vector >&     get_options() const;
2940
 
2941
    // Resolve any references, or generate/update appropriate conflict
2942
    // objects. The default implementation is a no-op because not all
2943
    // properties involve references.
2944
    virtual void update(CdlTransaction, CdlNode /* source */, CdlNode /* dest */, CdlUpdate);
2945
 
2946
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
2947
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
2948
 
2949
  protected:
2950
 
2951
    // The legal constructor can only get invoked from a derived class
2952
    // constructor. The first argument identifies the property, e.g.
2953
    // CdlPropertyId_Doc (which is just #define'd to the string
2954
    // "doc").
2955
    //
2956
    // The argc and argv fields provide access to the original
2957
    // data in the command that resulted in the property being
2958
    // constructed. Often but not always argv[0] will be the same as
2959
    // the property id. The argv information is stored mainly for
2960
    // diagnostics purposes, it may be removed in future to avoid
2961
    // wasting memory.
2962
    //
2963
    // The options field is the result of parsing options such
2964
    // as -library=libextras.a. It consists of a vector of
2965
    //  pairs, and is usually obtained via
2966
    // CdlParse::parse_options().
2967
    CdlPropertyBody(CdlNode, std::string, int argc, const char* argv[], std::vector >&);
2968
 
2969
  private:
2970
    // This string indicates the command used to define this property,
2971
    // e.g. "doc" or "define_proc". It is provided to the constructor.
2972
    std::string                 name;
2973
 
2974
    // All property data comes out of a file and gets rid via a
2975
    // Tcl interpreter. The raw file data is stored with the property,
2976
    // mainly for diagnostics purposes.
2977
    std::vector    argv;
2978
 
2979
    std::vector >   options;
2980
 
2981
    // The usual set of illegal operations.
2982
    CdlPropertyBody();
2983
    CdlPropertyBody(const CdlPropertyBody&);
2984
    CdlPropertyBody& operator=(const CdlPropertyBody&);
2985
 
2986
    enum {
2987
        CdlPropertyBody_Invalid = 0,
2988
        CdlPropertyBody_Magic   = 0x60dd58f4
2989
    } cdlpropertybody_cookie;
2990
};
2991
 
2992
//}}}
2993
//{{{  CdlProperty_Minimal
2994
 
2995
// ----------------------------------------------------------------------------
2996
// This class is used for properties that are simple flags, e.g. no_define.
2997
// There should be no additional data associated with such properties.
2998
 
2999
class CdlProperty_MinimalBody : public CdlPropertyBody {
3000
 
3001
    friend class CdlTest;
3002
 
3003
  public:
3004
    static CdlProperty_Minimal   make(CdlNode, std::string, int, const char*[], std::vector >&);
3005
    virtual ~CdlProperty_MinimalBody( );
3006
    bool                        check_this( cyg_assert_class_zeal = cyg_quick ) const;
3007
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3008
 
3009
  protected:
3010
 
3011
  private:
3012
    typedef CdlPropertyBody     inherited;
3013
 
3014
    CdlProperty_MinimalBody(CdlNode, std::string, int, const char*[], std::vector >&);
3015
    enum {
3016
        CdlProperty_MinimalBody_Invalid = 0,
3017
        CdlProperty_MinimalBody_Magic   = 0x25625b8c
3018
    } cdlproperty_minimalbody_cookie;
3019
 
3020
    CdlProperty_MinimalBody();
3021
    CdlProperty_MinimalBody(const CdlProperty_MinimalBody&);
3022
    CdlProperty_MinimalBody& operator=(const CdlProperty_MinimalBody&);
3023
};
3024
 
3025
//}}}
3026
//{{{  CdlProperty_String
3027
 
3028
// ----------------------------------------------------------------------------
3029
// A string property contains a single piece of additional data in the form
3030
// of a string.
3031
 
3032
class CdlProperty_StringBody : public CdlPropertyBody {
3033
 
3034
    friend class CdlTest;
3035
 
3036
  public:
3037
    static CdlProperty_String    make(CdlNode, std::string, std::string, int, const char*[],
3038
                                      std::vector >&);
3039
    virtual ~CdlProperty_StringBody();
3040
 
3041
    std::string                 get_string(void) const;
3042
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
3043
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3044
 
3045
  protected:
3046
 
3047
  private:
3048
    typedef CdlPropertyBody     inherited;
3049
 
3050
    CdlProperty_StringBody(CdlNode, std::string /* id */, std::string /* data */, int, const char*[],
3051
                           std::vector >&);
3052
    std::string                 data;
3053
    enum {
3054
        CdlProperty_StringBody_Invalid = 0,
3055
        CdlProperty_StringBody_Magic   = 0x78d1ca94
3056
    } cdlproperty_stringbody_cookie;
3057
 
3058
    // The only legal constructor supplies all the data.
3059
    CdlProperty_StringBody();
3060
    CdlProperty_StringBody(const CdlProperty_StringBody&);
3061
    CdlProperty_StringBody& operator=(const CdlProperty_StringBody&);
3062
};
3063
 
3064
//}}}
3065
//{{{  CdlProperty_TclCode
3066
 
3067
// ----------------------------------------------------------------------------
3068
// A TclCode property is currently equivalent to a string property. In
3069
// future this may change to allow the byte-compiled versions of the
3070
// script to be stored.
3071
//
3072
// One of the properties, "screen" inside a cdl_wizard, also takes
3073
// an integer. Rather than create yet another class, this is handled
3074
// by a separate constructor.
3075
 
3076
 
3077
class CdlProperty_TclCodeBody : public CdlPropertyBody {
3078
 
3079
    friend class CdlTest;
3080
 
3081
  public:
3082
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_tcl_code, int, const char*[],
3083
                                      std::vector >&);
3084
    static CdlProperty_TclCode   make(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
3085
                                      std::vector >&);
3086
    virtual ~CdlProperty_TclCodeBody();
3087
 
3088
    cdl_int                     get_number(void) const;
3089
    const cdl_tcl_code&         get_code(void)   const;
3090
    bool                        check_this(cyg_assert_class_zeal = cyg_quick) const;
3091
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3092
 
3093
  private:
3094
    typedef CdlPropertyBody     inherited;
3095
 
3096
    CdlProperty_TclCodeBody(CdlNode, std::string, cdl_int, cdl_tcl_code, int, const char*[],
3097
                            std::vector >&);
3098
 
3099
    cdl_int                     number;
3100
    cdl_tcl_code                code;
3101
    enum {
3102
        CdlProperty_TclCodeBody_Invalid = 0,
3103
        CdlProperty_TclCodeBody_Magic   = 0x7b14d4e5
3104
    } cdlproperty_tclcodebody_cookie;
3105
 
3106
    CdlProperty_TclCodeBody();
3107
    CdlProperty_TclCodeBody(const CdlProperty_TclCodeBody&);
3108
    CdlProperty_TclCodeBody& operator=(const CdlProperty_TclCodeBody&);
3109
 
3110
};
3111
 
3112
//}}}
3113
//{{{  CdlProperty_StringVector
3114
 
3115
// ----------------------------------------------------------------------------
3116
// This is used for multiple constant strings, as opposed to a list
3117
// expression which requires evaluation. One example is a list
3118
// of aliases.
3119
 
3120
class CdlProperty_StringVectorBody : public CdlPropertyBody {
3121
 
3122
    friend class CdlTest;
3123
 
3124
  public:
3125
    static CdlProperty_StringVector     make(CdlNode, std::string, const std::vector&, int, const char*[],
3126
                                             std::vector >&);
3127
    virtual ~CdlProperty_StringVectorBody();
3128
 
3129
    const std::vector&     get_strings() const;
3130
    std::string                         get_first_string() const;
3131
    unsigned int                        get_number_of_strings() const;
3132
    std::string                         get_string(unsigned int) const;
3133
    bool                                check_this(cyg_assert_class_zeal zeal = cyg_quick) const;
3134
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3135
 
3136
  private:
3137
    typedef CdlPropertyBody            inherited;
3138
 
3139
    CdlProperty_StringVectorBody(CdlNode, std::string, const std::vector&, int, const char*[],
3140
                                 std::vector >&);
3141
 
3142
    std::vector            data;
3143
    enum {
3144
        CdlProperty_StringVectorBody_Invalid = 0,
3145
        CdlProperty_StringVectorBody_Magic   = 0x4ed039f3
3146
    } cdlproperty_stringvectorbody_cookie;
3147
 
3148
    CdlProperty_StringVectorBody();
3149
    CdlProperty_StringVectorBody(const CdlProperty_StringVectorBody&);
3150
    CdlProperty_StringVectorBody& operator=(const CdlProperty_StringVectorBody&);
3151
};
3152
 
3153
//}}}
3154
//{{{  CdlProperty_Reference
3155
 
3156
// ----------------------------------------------------------------------------
3157
// This is used for properties such as wizard and dialog, where the data
3158
// identifies some other entity in the system. The class is both a property
3159
// and a reference object. Most of the desired functionality is provided by
3160
// inheritance from CdlReference.
3161
 
3162
class CdlProperty_ReferenceBody : public CdlPropertyBody, public CdlReference {
3163
 
3164
    friend class CdlTest;
3165
 
3166
  public:
3167
    static CdlProperty_Reference make(CdlNode, std::string /* id */, std::string /* destination */,
3168
                                      CdlUpdateHandler, int, const char*[],
3169
                                      std::vector >&);
3170
    virtual ~CdlProperty_ReferenceBody();
3171
 
3172
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3173
 
3174
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3175
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3176
 
3177
  private:
3178
    typedef CdlPropertyBody     inherited_property;
3179
    typedef CdlReference        inherited_reference;
3180
 
3181
    CdlUpdateHandler            update_handler;
3182
 
3183
    CdlProperty_ReferenceBody(CdlNode, std::string /* id */, std::string /* destination */, CdlUpdateHandler, int, const char*[],
3184
                              std::vector >&);
3185
    enum {
3186
        CdlProperty_ReferenceBody_Invalid = 0,
3187
        CdlProperty_ReferenceBody_Magic   = 0x78100339
3188
    } cdlproperty_referencebody_cookie;
3189
 
3190
    CdlProperty_ReferenceBody();
3191
    CdlProperty_ReferenceBody(const CdlProperty_ReferenceBody&);
3192
    CdlProperty_ReferenceBody& operator=(const CdlProperty_Reference&);
3193
};
3194
 
3195
//}}}
3196
//{{{  CdlProperty_Expression
3197
 
3198
// ----------------------------------------------------------------------------
3199
// An expression property simply inherits its functionality from the basic
3200
// property class and from the expression class.
3201
 
3202
class CdlProperty_ExpressionBody : public CdlPropertyBody, public CdlExpressionBody {
3203
 
3204
    friend class CdlTest;
3205
 
3206
  public:
3207
    static CdlProperty_Expression       make(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
3208
                                             std::vector >&);
3209
    virtual ~CdlProperty_ExpressionBody();
3210
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3211
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3212
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3213
 
3214
  private:
3215
    typedef CdlPropertyBody     inherited_property;
3216
    typedef CdlExpressionBody   inherited_expression;
3217
 
3218
    CdlProperty_ExpressionBody(CdlNode, std::string, CdlExpression, CdlUpdateHandler, int, const char*[],
3219
                               std::vector >&);
3220
 
3221
    CdlUpdateHandler update_handler;
3222
    enum {
3223
        CdlProperty_ExpressionBody_Invalid = 0,
3224
        CdlProperty_ExpressionBody_Magic   = 0x05fb4056
3225
    } cdlproperty_expressionbody_cookie;
3226
 
3227
    CdlProperty_ExpressionBody();
3228
    CdlProperty_ExpressionBody(const CdlProperty_ExpressionBody&);
3229
    CdlProperty_ExpressionBody& operator=(const CdlProperty_ExpressionBody&);
3230
};
3231
 
3232
//}}}
3233
//{{{  CdlProperty_ListExpression
3234
 
3235
// ----------------------------------------------------------------------------
3236
// Similarly a list property simply inherits from property and from
3237
// list expressions.
3238
 
3239
class CdlProperty_ListExpressionBody : public CdlPropertyBody, public CdlListExpressionBody {
3240
 
3241
    friend class CdlTest;
3242
 
3243
  public:
3244
    static CdlProperty_ListExpression   make(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
3245
                                             std::vector >&);
3246
    virtual ~CdlProperty_ListExpressionBody();
3247
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3248
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3249
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3250
 
3251
  private:
3252
    typedef CdlPropertyBody         inherited_property;
3253
    typedef CdlListExpressionBody   inherited_expression;
3254
 
3255
    CdlProperty_ListExpressionBody(CdlNode, std::string, CdlListExpression, CdlUpdateHandler, int, const char*[],
3256
                                   std::vector >&);
3257
 
3258
    CdlUpdateHandler update_handler;
3259
    enum {
3260
        CdlProperty_ListExpressionBody_Invalid = 0,
3261
        CdlProperty_ListExpressionBody_Magic   = 0x6b0136f5
3262
    } cdlproperty_listexpressionbody_cookie;
3263
 
3264
    CdlProperty_ListExpressionBody();
3265
    CdlProperty_ListExpressionBody(const CdlProperty_ListExpressionBody&);
3266
    CdlProperty_ListExpressionBody& operator=(const CdlProperty_ListExpressionBody&);
3267
};
3268
 
3269
//}}}
3270
//{{{  CdlProperty_GoalExpression
3271
 
3272
// ----------------------------------------------------------------------------
3273
// And a goal property inherits from property and from goal expressions.
3274
 
3275
class CdlProperty_GoalExpressionBody : public CdlPropertyBody, public CdlGoalExpressionBody {
3276
 
3277
    friend class CdlTest;
3278
 
3279
  public:
3280
    static CdlProperty_GoalExpression   make(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
3281
                                             std::vector >&);
3282
    virtual ~CdlProperty_GoalExpressionBody();
3283
    void update(CdlTransaction, CdlNode, CdlNode, CdlUpdate);
3284
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3285
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3286
 
3287
  private:
3288
    typedef CdlPropertyBody         inherited_property;
3289
    typedef CdlGoalExpressionBody   inherited_expression;
3290
 
3291
    CdlProperty_GoalExpressionBody(CdlNode, std::string, CdlGoalExpression, CdlUpdateHandler, int, const char*[],
3292
                                   std::vector >&);
3293
 
3294
    CdlUpdateHandler update_handler;
3295
    enum {
3296
        CdlProperty_GoalExpressionBody_Invalid = 0,
3297
        CdlProperty_GoalExpressionBody_Magic   = 0x08b2b31e
3298
    } cdlproperty_goalexpressionbody_cookie;
3299
 
3300
    CdlProperty_GoalExpressionBody();
3301
    CdlProperty_GoalExpressionBody(const CdlProperty_GoalExpressionBody&);
3302
    CdlProperty_GoalExpressionBody& operator=(const CdlProperty_GoalExpressionBody&);
3303
};
3304
 
3305
//}}}
3306
 
3307
//}}}
3308
//{{{  CdlParse class
3309
 
3310
// ----------------------------------------------------------------------------
3311
// This is another utility class for collecting together parsing-related
3312
// functions.
3313
//
3314
// Note that this is only a utility class. When libcdl is used for parsing
3315
// things not related to software configuration the new functionality
3316
// does not have to reside inside the CdlParse class, but it may be
3317
// possible to re-use some of the functionality in that class.
3318
 
3319
class CdlParse {
3320
 
3321
  public:
3322
    // Utility routines.
3323
    static std::string  get_tcl_cmd_name(std::string);
3324
    static std::string  concatenate_argv(int, const char*[], int);
3325
    static int          parse_options(CdlInterpreter, std::string /* diag_prefix */, const char** /* options */,
3326
                                               int /* argc */, const char*[] /* argv */, int /* start_index */,
3327
                                               std::vector >& /* result */);
3328
    static std::string  construct_diagnostic(CdlInterpreter, std::string /* classification */,
3329
                                             std::string /* sub-identifier */, std::string /* message */);
3330
 
3331
    static void         report_error(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
3332
    static void         report_warning(CdlInterpreter, std::string /* sub-identifier */, std::string /* message */);
3333
    static void         clear_error_count(CdlInterpreter);
3334
    static int          get_error_count(CdlInterpreter);
3335
    static void         incr_error_count(CdlInterpreter, int=1);
3336
 
3337
    static std::string  get_expression_error_location(void);
3338
 
3339
    // Support for Tcl's "unknown" command
3340
    static int          unknown_command(CdlInterpreter, int, const char*[]);
3341
 
3342
    // Property-related utilities
3343
    static void         report_property_parse_error(CdlInterpreter, std::string, std::string);
3344
    static void         report_property_parse_error(CdlInterpreter, CdlProperty, std::string);
3345
    static void         report_property_parse_warning(CdlInterpreter, std::string, std::string);
3346
    static void         report_property_parse_warning(CdlInterpreter, CdlProperty, std::string);
3347
 
3348
    // Utility parsing routines
3349
    static int  parse_minimal_property(CdlInterpreter, int, const char*[], std::string,
3350
                                       const char**, void (*)(CdlInterpreter, CdlProperty_Minimal));
3351
    static int  parse_string_property(CdlInterpreter, int, const char*[], std::string,
3352
                                      const char**, void (*)(CdlInterpreter, CdlProperty_String));
3353
    static int  parse_tclcode_property(CdlInterpreter, int, const char*[], std::string,
3354
                                       const char**, void (*)(CdlInterpreter, CdlProperty_TclCode));
3355
    static int  parse_stringvector_property(CdlInterpreter, int, const char*[], std::string,
3356
                                            const char**, void (*)(CdlInterpreter, CdlProperty_StringVector),
3357
                                            bool /* allow_empty */ = false);
3358
    static int  parse_reference_property(CdlInterpreter, int, const char*[], std::string,
3359
                                         const char**, void (*)(CdlInterpreter, CdlProperty_Reference),
3360
                                         bool /* allow_empty */,
3361
                                         CdlUpdateHandler);
3362
    static int  parse_expression_property(CdlInterpreter, int, const char*[], std::string,
3363
                                          const char **, void (*)(CdlInterpreter, CdlProperty_Expression),
3364
                                          CdlUpdateHandler);
3365
    static int  parse_listexpression_property(CdlInterpreter, int, const char*[], std::string,
3366
                                              const char **, void (*)(CdlInterpreter, CdlProperty_ListExpression),
3367
                                              CdlUpdateHandler);
3368
    static int  parse_goalexpression_property(CdlInterpreter, int, const char*[], std::string,
3369
                                              const char **, void (*)(CdlInterpreter, CdlProperty_GoalExpression),
3370
                                              CdlUpdateHandler);
3371
};
3372
 
3373
//}}}
3374
//{{{  CdlNode
3375
 
3376
// ----------------------------------------------------------------------------
3377
// A node object has a name and lives in a hierarchy. Each node keeps
3378
// track of the toplevel and owner. The memory overheads are
3379
// relatively small compared with the performance gains when such
3380
// information is needed.
3381
//
3382
// A node object also has a vector of properties, and can be referred to
3383
// by properties in other nodes. Some of the properties may result in
3384
// conflicts.
3385
 
3386
class CdlNodeBody {
3387
 
3388
    friend class CdlTest;
3389
 
3390
    // Adding and removing nodes from the hierarchy is done
3391
    // by CdlToplevel members.
3392
    friend class CdlToplevelBody;
3393
 
3394
    // CdlLoadable must be able to access the destructor
3395
    friend class CdlLoadableBody;
3396
 
3397
    // It is intended that CdlProperties will also add and remove themselves
3398
    friend class CdlPropertyBody;
3399
 
3400
    // CdlReference bind and unbind operations need access to
3401
    // the referrers vector. So does CdlTransaction::commit()
3402
    friend class CdlReference;
3403
    friend class CdlTransactionBody;
3404
 
3405
  public:
3406
 
3407
    // Basic information.
3408
    std::string         get_name() const;
3409
    CdlContainer        get_parent() const;
3410
    CdlLoadable         get_owner() const;
3411
    CdlToplevel         get_toplevel() const;
3412
 
3413
    // Propagation support. Some updates such as active/inactive changes
3414
    // get applied to nodes as well as to properties. Note that because
3415
    // of multiple inheritance this virtual call can get confusing.
3416
    virtual void        update(CdlTransaction, CdlUpdate);
3417
 
3418
    // Is this node active or not? The is_active() call refers
3419
    // to the global state, things may be different inside a
3420
    // transaction.
3421
    bool                is_active() const;
3422
    bool                is_active(CdlTransaction transaction);
3423
 
3424
    // Generally nodes become active when the parent becomes
3425
    // active and enabled. Some derived classes may impose
3426
    // additional restrictions, for example because of
3427
    // active_if constraints. This routine can be used
3428
    // to check whether or not a node should become active.
3429
    virtual bool        test_active(CdlTransaction);
3430
 
3431
    // Provide access to the various properties. Currently all this
3432
    // information is publicly available.
3433
    const std::vector&     get_properties() const;
3434
    CdlProperty                         get_property(std::string) const;
3435
    void                                get_properties(std::string, std::vector&) const;
3436
    std::vector            get_properties(std::string) const;
3437
    bool                                has_property(std::string) const;
3438
    int                                 count_properties(std::string) const;
3439
 
3440
    // Provide access to the various global conflicts. More
3441
    // commonly conflicts are accessed on a per-transaction basis.
3442
    void get_conflicts(std::vector&) const;
3443
    void get_conflicts(bool (*)(CdlConflict), std::vector&) const;
3444
    void get_structural_conflicts(std::vector&) const;
3445
    void get_structural_conflicts(bool (*)(CdlConflict), std::vector&) const;
3446
 
3447
    // Provide access to all the referrers. This may not get used very
3448
    // much outside the library itself.
3449
    const std::vector&     get_referrers() const;
3450
 
3451
    // Add property parsers and validation code appropriate for a
3452
    // node. Currently this is a no-op, there are no properties
3453
    // associated with every node, but this may change in future e.g.
3454
    // for diagnostics purposes.
3455
    static void add_property_parsers(std::vector& parsers);
3456
    void        check_properties(CdlInterpreter);
3457
 
3458
    // Persistence support. The final classes such as cdl_option
3459
    // should provide implementations of these functions. The
3460
    // base function takes care of data that was present in an
3461
    // original save file but which was not recognised.
3462
    //
3463
    // Configuration save files are Tcl scripts, so it seems
3464
    // appropriate to handle the I/O via the Tcl library and
3465
    // to have a TCL interpreter available.
3466
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3467
    bool has_additional_savefile_information() const;
3468
 
3469
    // Mainly for diagnostics code, what is the actual name for this
3470
    // type of CDL object? This should be in terms of CDL data, e.g.
3471
    // "package" or "component", rather than in implementation terms
3472
    // such as "CdlPackageBody".
3473
    virtual std::string get_class_name() const;
3474
 
3475
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
3476
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3477
 
3478
  protected:
3479
 
3480
    // CdlNodeBodies are only instantiated by derived classes.
3481
    // They must always have a name. They need not be placed
3482
    // in the hierarchy immediately, that can wait until
3483
    // later.
3484
    CdlNodeBody(std::string);
3485
    // A dummy constructor is needed because of the virtual
3486
    // inheritance.
3487
    CdlNodeBody();
3488
 
3489
    // Nodes cannot be destroyed directly by application code,
3490
    // only by higher-level library functions such as unload_package()
3491
    virtual ~CdlNodeBody();
3492
 
3493
    // Updating the name is rarely required, but is useful for savefiles.
3494
    void                set_name(std::string);
3495
 
3496
    // Is the node currently active? This applies to the global state
3497
    // only, not per-transaction state. Some derived classes may want
3498
    // to override the default value
3499
    bool                active;
3500
 
3501
  private:
3502
 
3503
    // The basic data. The name is known during construction.
3504
    // The other three fields get updated by e.g. CdlToplevel::add_node();
3505
    std::string         name;
3506
    CdlContainer        parent;
3507
    CdlLoadable         owner;
3508
    CdlToplevel         toplevel;
3509
 
3510
    // This is used by remove_node_from_toplevel()/add_node_to_toplevel()
3511
    // to allow the latter to exactly reverse the former
3512
    int                 remove_node_container_position;
3513
 
3514
    // Properties normally only get added during the parsing process,
3515
    // and only get removed when the object itself is destroyed.
3516
    // A vector is the obvious implementation.
3517
    std::vector properties;
3518
 
3519
    // Currently a vector of referrers is used. This vector is subject
3520
    // to change when packages get loaded and unloaded, possibly a
3521
    // list would be better.
3522
    std::vector referrers;
3523
 
3524
    // Savefiles may contain information that is not recognised by the
3525
    // current library, especially because of savefile hooks which
3526
    // allow e.g. the configuration tool to store its own information
3527
    // in save files. This information must not be lost, even if you are
3528
    // e.g. mixing command line and GUI tools. This vector holds
3529
    // the savefile information so that it can be put in the next
3530
    // savefile.
3531
    std::vector unsupported_savefile_strings;
3532
 
3533
    enum {
3534
        CdlNodeBody_Invalid     = 0,
3535
        CdlNodeBody_Magic       = 0x309595b5
3536
    } cdlnodebody_cookie;
3537
 
3538
    // Illegal operations
3539
    CdlNodeBody(const CdlNodeBody&);
3540
    CdlNodeBody& operator=(const CdlNodeBody&);
3541
};
3542
 
3543
//}}}
3544
//{{{  CdlContainer
3545
 
3546
// ----------------------------------------------------------------------------
3547
// A container is a node that can contain other nodes.
3548
 
3549
class CdlContainerBody : virtual public CdlNodeBody {
3550
 
3551
    friend class Cdltest;
3552
 
3553
    // Allow CdlNode::check_this() access to the internals
3554
    friend class CdlNodeBody;
3555
 
3556
    // Adding a node to the hierarchy is done by a CdlToplevel member.
3557
    // Ditto for removing.
3558
    friend class CdlToplevelBody;
3559
 
3560
    // Deleting a container can happen inside CdlToplevel and CdlLoadable
3561
    friend class CdlLoadableBody;
3562
 
3563
  public:
3564
 
3565
    const std::vector& get_contents() const;
3566
    bool                        contains(CdlConstNode, bool /* recurse */ = false) const;
3567
    bool                        contains(const std::string, bool /* recurse */ = false) const;
3568
    CdlNode                     find_node(const std::string, bool /* recurse */ = false) const;
3569
 
3570
    // Propagation support. Some updates such as active/inactive changes
3571
    // get applied to nodes as well as to properties.
3572
    virtual void update(CdlTransaction, CdlUpdate);
3573
 
3574
    // Persistence support.
3575
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3576
 
3577
    virtual std::string get_class_name() const;
3578
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3579
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3580
 
3581
  protected:
3582
 
3583
    // Containers cannot be destroyed explicitly, only via higher-level
3584
    // code such as unload_package();
3585
    virtual ~CdlContainerBody();
3586
 
3587
    CdlContainerBody();
3588
    // Special constructor needed for internal use.
3589
    CdlContainerBody(std::string);
3590
 
3591
    // The CdlToplevel class needs access to its own contents.
3592
    std::vector                contents;
3593
 
3594
  private:
3595
    enum {
3596
        CdlContainerBody_Invalid        = 0,
3597
        CdlContainerBody_Magic          = 0x543c5f1d
3598
    } cdlcontainerbody_cookie;
3599
 
3600
    // Illegal operations
3601
    CdlContainerBody(const CdlContainerBody&);
3602
    CdlContainerBody& operator=(const CdlContainerBody&);
3603
};
3604
 
3605
//}}}
3606
//{{{  CdlLoadable
3607
 
3608
// ----------------------------------------------------------------------------
3609
// A loadable object is a container that gets loaded or unloaded
3610
// atomically from a toplevel. The key difference is that a loadable
3611
// keeps track of all nodes that were loaded as part of this
3612
// operation, thus allowing unload operations to happen safely even if
3613
// nodes get re-parented all over the hierarchy. In addition, there is
3614
// a slave interpreter associated with every loadable.
3615
 
3616
class CdlLoadableBody : virtual public CdlContainerBody {
3617
 
3618
    friend class CdlTest;
3619
 
3620
    // Allow CdlNode::check_this() access to the internals
3621
    friend class CdlNodeBody;
3622
 
3623
    // Adding nodes to the hierarchy is done by a toplevel member
3624
    friend class CdlToplevelBody;
3625
 
3626
  public:
3627
    virtual ~CdlLoadableBody();
3628
 
3629
 
3630
    const std::vector&         get_owned() const;
3631
    bool                                owns(CdlConstNode) const;
3632
    CdlInterpreter                      get_interpreter() const;
3633
    std::string                         get_repository() const;
3634
    std::string                         get_directory() const;
3635
 
3636
    // Some properties such as doc and compile reference filenames.
3637
    // A search facility is useful.
3638
    virtual std::string find_relative_file(std::string /* filename */, std::string /* directory */ = "") const;
3639
    virtual std::string find_absolute_file(std::string, std::string, bool /* allow_urls */ = false) const;
3640
    virtual bool        has_subdirectory(std::string) const;
3641
 
3642
    // These support load/unload operations inside transactions
3643
    // They are static members because some of them will want
3644
    // to delete the loadable.
3645
    static void         transaction_commit_load(CdlTransaction, CdlLoadable);
3646
    static void         transaction_cancel_load(CdlTransaction, CdlLoadable);
3647
    static void         transaction_commit_unload(CdlTransaction, CdlLoadable);
3648
    static void         transaction_cancel_unload(CdlTransaction, CdlLoadable);
3649
 
3650
    // Binding and unbinding of properties. This involves processing
3651
    // the various properties, calculating default values, etc.
3652
    void                bind(CdlTransaction);
3653
    void                unbind(CdlTransaction);
3654
 
3655
    virtual std::string get_class_name() const;
3656
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3657
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3658
 
3659
  protected:
3660
 
3661
    CdlLoadableBody(CdlToplevel, std::string /* repository */, std::string /* directory */);
3662
 
3663
    // Needed by derived classes, but not actually used.
3664
    CdlLoadableBody();
3665
 
3666
  private:
3667
 
3668
    std::vector owned;
3669
    CdlInterpreter       interp;
3670
    std::string          repository;
3671
    std::string          directory;
3672
 
3673
    // Used by add/remove_node_from_toplevel()
3674
    int                  remove_node_loadables_position;
3675
 
3676
    enum {
3677
        CdlLoadableBody_Invalid = 0,
3678
        CdlLoadableBody_Magic   = 0x488d6127
3679
    } cdlloadablebody_cookie;
3680
 
3681
    // Invalid operations
3682
    CdlLoadableBody(const CdlLoadableBody&);
3683
    CdlLoadableBody& operator=(const CdlLoadableBody&);
3684
};
3685
 
3686
//}}}
3687
//{{{  CdlToplevel
3688
 
3689
// ----------------------------------------------------------------------------
3690
// Toplevels are containers that live at the top of a hierarchy
3691
// (surprise surprise). This means that they do not have a parent.
3692
// In addition a toplevel object keeps track of all the names
3693
// used, guaranteeing uniqueness and providing a quick lookup
3694
// facility.
3695
//
3696
// Every container is also a node, so every toplevel is a node.
3697
// Inheritance from CdlNode may seem wrong. However it achieves
3698
// consistency, everything in the hierarchy including the toplevel
3699
// is a node. The main disadvantage is that every toplevel now
3700
// needs a name.
3701
 
3702
class CdlToplevelBody : virtual public CdlContainerBody {
3703
 
3704
    friend class CdlTest;
3705
 
3706
    // Allow CdlNode::check_this() access to the internals
3707
    friend class CdlNodeBody;
3708
 
3709
    // The CdlTransaction class needs direct access to the lists
3710
    // of conflicts.
3711
    friend class CdlTransactionBody;
3712
 
3713
  public:
3714
    virtual ~CdlToplevelBody();
3715
 
3716
    // Updating the hierarchy. This happens a node at a time. Adding a
3717
    // node involves updating the name->node map in the toplevel,
3718
    // setting the node's parent/owner/toplevel fields, and updating
3719
    // the parent and owner containers. The owner may be 0 for special
3720
    // nodes such as the orphans container. The parent must be known,
3721
    // although it may change later on during a change_parent() call.
3722
    //
3723
    // Removing a node is more complicated, and involves a two-stage
3724
    // process. First the node is removed from the toplevel, thus
3725
    // eliminating the name->node mapping. The owner and parent fields
3726
    // are preserved at this stage (except for the loadable itself),
3727
    // and the operation may be undone if the relevant transaction
3728
    // gets cancelled. If the transaction gets committed then the
3729
    // second remove operation handles the owner and parent fields,
3730
    // just prior to the node being deleted. For convenience there
3731
    // are also per-loadable variants for some of these.
3732
    //
3733
    // change_parent() is used to support parent-properties.
3734
    // A container of 0 indicates an orphan, i.e. a parent
3735
    // property that did not or does not correspond to a
3736
    // current container.
3737
    //
3738
    // There is also a clean-up call. This gets used for interfaces
3739
    // which may alternate between belonging to a loadable and
3740
    // being auto-created.
3741
    void add_node(CdlLoadable, CdlContainer, CdlNode);
3742
    void add_node_to_toplevel(CdlNode);
3743
    void remove_node_from_toplevel(CdlNode);
3744
    static void remove_node(CdlLoadable, CdlContainer, CdlNode);
3745
    void add_loadable_to_toplevel(CdlLoadable);
3746
    void remove_loadable_from_toplevel(CdlLoadable);
3747
    void change_parent(CdlLoadable, CdlContainer /* current */, CdlContainer /* new */, CdlNode, int /* pos */ = -1);
3748
    void cleanup_orphans();
3749
 
3750
    // Toplevels keep track of all the loadables, in addition to
3751
    // inheriting tree behaviour from CdlContainer. This is convenient
3752
    // for some operations like determining build information
3753
    // which must operate on a per-loadable basis.
3754
    const std::vector& get_loadables() const;
3755
 
3756
    // Name uniqueness is guaranteed. It is convenient to have an STL
3757
    // map as a lookup service.
3758
    CdlNode lookup(const std::string) const;
3759
 
3760
    // There are two conflict lists associated with each toplevel. One
3761
    // is for "structural" conflicts, ones that can only be resolved
3762
    // by a fairly major change such as loading another package: a
3763
    // typical example is an unresolved parent reference. The other is
3764
    // for conflicts that can probably be resolved simply by changing
3765
    // some values. Both sets of conflicts are held as a simple list.
3766
    //
3767
    // The active vs. inactive state of a CDL entity affects the
3768
    // location of structural vs. non-structural conflicts. If an
3769
    // entity becomes inactive then structural conflicts are not
3770
    // affected, but non-structural conflicts are removed from the
3771
    // global list. If an entity's "requires" expression is not
3772
    // satisfied but the entity is inactive anyway then this is
3773
    // harmless.
3774
    const std::list& get_all_conflicts() const;
3775
    const std::list& get_all_structural_conflicts() const;
3776
 
3777
    // Try to resolve some or all conflicts. Typically a new transaction
3778
    // will be created for this.
3779
    void        resolve_conflicts(const std::vector&);
3780
    void        resolve_all_conflicts();
3781
 
3782
    // Toplevels can have descriptions provided by the user. This is
3783
    // particularly important for pre-defined templates, target
3784
    // board descriptions, etc. where the user would like some
3785
    // extra information about the template before loading it in.
3786
    // The default value is an empty string.
3787
    std::string         get_description() const;
3788
    void                set_description(std::string);
3789
 
3790
    // Each toplevel must have an associated master Tcl interpreter.
3791
    CdlInterpreter      get_interpreter() const;
3792
 
3793
    // Each toplevel may have a single active main transaction.
3794
    // For now there is no support for concurrent transactions
3795
    // operating on a single toplevel (although nested transactions
3796
    // are allowed)
3797
    CdlTransaction      get_active_transaction() const;
3798
 
3799
    // Build and define operations are available for all toplevels,
3800
    // even if they are not always applicable
3801
    void                get_build_info(CdlBuildInfo&);
3802
    void                get_all_build_info(CdlBuildInfo&);
3803
    void                generate_config_headers(std::string);
3804
    void                get_config_headers(std::vector&);
3805
    void                generate_build_tree(std::string, std::string = "");
3806
 
3807
    // Values can be stored in limbo. This is useful when unloading
3808
    // and reloading packages, e.g. when changing a version the
3809
    // current settings can be preserved as much as possible.
3810
    void                set_limbo_value(CdlValuable);
3811
    bool                has_limbo_value(std::string) const;
3812
    CdlValue            get_limbo_value(std::string) const;
3813
    CdlValue            get_and_remove_limbo_value(std::string);
3814
    void                clear_limbo();
3815
 
3816
    // Persistence support. These are commented in the source code.
3817
           void         initialize_savefile_support();
3818
    static bool         savefile_support_initialized();
3819
           void         add_savefile_command(std::string, CdlSaveCallback, CdlInterpreterCommand);
3820
           void         add_savefile_subcommand(std::string, std::string, CdlSaveCallback, CdlInterpreterCommand);
3821
           void         get_savefile_commands(std::vector&);
3822
           void         get_savefile_subcommands(std::string, std::vector&);
3823
           void         save_command_details(CdlInterpreter, Tcl_Channel, int, bool);
3824
    static int          savefile_handle_command(CdlInterpreter, int, const char*[]);
3825
    static int          savefile_handle_unsupported(CdlInterpreter, int, const char*[]);
3826
    static int          savefile_handle_unknown(CdlInterpreter, int, const char*[]);
3827
           void         save_unsupported_commands(CdlInterpreter, Tcl_Channel, int, bool);
3828
    static cdl_int      get_library_savefile_version();
3829
    static int          savefile_handle_version(CdlInterpreter, int, const char*[]);
3830
    static cdl_int      get_savefile_version(CdlInterpreter);
3831
           void         save_conflicts(CdlInterpreter, Tcl_Channel, int, bool);
3832
    static void         save_separator(CdlInterpreter, Tcl_Channel, std::string, bool);
3833
 
3834
    virtual std::string get_class_name() const;
3835
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3836
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3837
 
3838
  protected:
3839
    CdlToplevelBody(CdlInterpreter);
3840
 
3841
  private:
3842
 
3843
    std::map       lookup_table;
3844
    std::vector            loadables;
3845
    std::map      limbo;
3846
    CdlInterpreter                      interp;
3847
    CdlContainer                        orphans;
3848
    std::string                         description;
3849
    std::list              conflicts;
3850
    std::list              structural_conflicts;
3851
 
3852
    // The savefile support corresponding to this application.
3853
    static cdl_int savefile_version;
3854
    static bool    savefile_commands_initialized;
3855
    static std::vector savefile_commands;
3856
    static std::map > savefile_subcommands;
3857
 
3858
    // Per-toplevel support. A savefile may contain unrecognised
3859
    // commands at the toplevel of a file, as well as unrecognised
3860
    // commands in e.g. the body of a cdl_configuration command.
3861
    // The latter is handled via the CdlNode base class.
3862
    std::vector unsupported_savefile_toplevel_strings;
3863
    std::vector unsupported_savefile_commands;
3864
    std::map > unsupported_savefile_subcommands;
3865
 
3866
    // Keep track of the current active transaction for this toplevel (if any)
3867
    CdlTransaction      transaction;
3868
 
3869
    enum {
3870
        CdlToplevelBody_Invalid = 0,
3871
        CdlToplevelBody_Magic   = 0x0834666e
3872
    } cdltoplevelbody_cookie;
3873
 
3874
    // Invalid operations
3875
    CdlToplevelBody(const CdlToplevelBody&);
3876
    CdlToplevelBody& operator=(const CdlToplevelBody&);
3877
};
3878
 
3879
//}}}
3880
//{{{  CdlUserVisible
3881
 
3882
// ----------------------------------------------------------------------------
3883
// A user-visible object is likely to have properties such as display,
3884
// description and doc. Many user-visible objects will have values but
3885
// not all, for example custom dialogs are likely to have a doc
3886
// property but they do not have a value.
3887
 
3888
class CdlUserVisibleBody : virtual public CdlNodeBody {
3889
 
3890
    friend class CdlTest;
3891
 
3892
  public:
3893
    virtual ~CdlUserVisibleBody();
3894
 
3895
    std::string         get_display() const;
3896
    std::string         get_description() const;
3897
    std::string         get_doc() const;
3898
 
3899
    // NOTE: this will only work for absolute doc strings or for doc
3900
    // strings that are relative to the package.
3901
    std::string         get_doc_url() const;
3902
 
3903
    // Add property parsers and validation code appropriate for a
3904
    // user-visible object such as doc and description
3905
    static void         add_property_parsers(std::vector& parsers);
3906
    void                check_properties(CdlInterpreter);
3907
    static int          parse_description(CdlInterpreter, int, const char*[]);
3908
    static int          parse_display(CdlInterpreter, int, const char*[]);
3909
    static int          parse_doc(CdlInterpreter, int, const char*[]);
3910
 
3911
    // Persistence support. The save code simply outputs some comments
3912
    // corresponding to the display, doc and description properties.
3913
    virtual void save(CdlInterpreter, Tcl_Channel, int, bool);
3914
 
3915
    virtual std::string get_class_name() const;
3916
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3917
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3918
 
3919
  protected:
3920
    CdlUserVisibleBody();
3921
 
3922
  private:
3923
 
3924
    enum {
3925
        CdlUserVisibleBody_Invalid      = 0,
3926
        CdlUserVisibleBody_Magic        = 0x13bbc817
3927
    } cdluservisiblebody_cookie;
3928
 
3929
    // Illegal operations
3930
    CdlUserVisibleBody(const CdlUserVisibleBody&);
3931
    CdlUserVisibleBody& operator=(const CdlUserVisibleBody&);
3932
};
3933
 
3934
//}}}
3935
//{{{  CdlParentable
3936
 
3937
// ----------------------------------------------------------------------------
3938
// A parentable object may have the parent property, redefining its
3939
// position in the hierarchy.
3940
 
3941
class CdlParentableBody : virtual public CdlNodeBody {
3942
 
3943
    friend class CdlTest;
3944
 
3945
  public:
3946
    virtual ~CdlParentableBody();
3947
 
3948
    static void         add_property_parsers(std::vector& parsers);
3949
    void                check_properties(CdlInterpreter);
3950
    static int          parse_parent(CdlInterpreter, int, const char*[]);
3951
    static void         update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
3952
 
3953
    virtual std::string get_class_name() const;
3954
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
3955
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
3956
 
3957
  protected:
3958
    CdlParentableBody();
3959
 
3960
  private:
3961
 
3962
    // Unloads may be cancelled. To restore the previous state exactly
3963
    // it is necessary to keep track of the old position.
3964
    int                 change_parent_save_position;
3965
 
3966
    enum {
3967
        CdlParentableBody_Invalid      = 0,
3968
        CdlParentableBody_Magic        = 0x40c6a077
3969
    } cdlparentablebody_cookie;
3970
 
3971
    // Illegal operations
3972
    CdlParentableBody(const CdlParentableBody&);
3973
    CdlParentableBody& operator=(const CdlParentableBody&);
3974
};
3975
 
3976
//}}}
3977
//{{{  CdlValuable
3978
 
3979
// ----------------------------------------------------------------------------
3980
// A valuable body has a value. Many valuables can be modified but not all.
3981
// Some properties make a valuable object read-only. In future there is
3982
// likely to be support for locked values as well. There is a member function
3983
// to check whether or not a valuable object is modifiable.
3984
//
3985
// Relevant properties for a valuable object are:
3986
//
3987
//  1) flavor           - readily available via CdlValue::get_flavor()
3988
//  2) default_value    - an expression
3989
//  3) legal_values     - a list expression
3990
//  4) entry_proc       - for validation purposes, in addition to legal_values
3991
//  5) check_proc       - ditto
3992
//  6) active_if        - goal expression
3993
//  7) requires         - goal expression
3994
//  8) dialog           - a custom dialog for editing this value
3995
//  9) calculated       - non-modifiable
3996
// 10) implements       - for interfaces
3997
//
3998
// A CdlValuable does not inherit directly from CdlValue, since it should
3999
// not be possible to modify a Valuable directly. Instead it contains a
4000
// CdlValue member, and provides essentially the same functions as
4001
// a CdlValue.
4002
 
4003
class CdlValuableBody : virtual public CdlNodeBody {
4004
 
4005
    friend class CdlTest;
4006
 
4007
    // Transaction commit operations require direct access to the CdlValue
4008
    friend class CdlTransactionBody;
4009
 
4010
  private:
4011
    CdlValue value;
4012
 
4013
  public:
4014
    virtual ~CdlValuableBody();
4015
 
4016
    // Accessing the current value. There are variants for the global state
4017
    // and for per-transaction operations.
4018
    const CdlValue&     get_whole_value() const;
4019
 
4020
    CdlValueFlavor      get_flavor() const;
4021
    CdlValueFlavor      get_flavor(CdlTransaction transaction) const
4022
    {   // The transaction is irrelevant, it cannot change the flavor
4023
        return this->get_flavor();
4024
    }
4025
 
4026
    CdlValueSource      get_source() const;
4027
    bool                has_source(        CdlValueSource) const;
4028
    bool                is_enabled(        CdlValueSource = CdlValueSource_Current) const;
4029
    std::string         get_value(         CdlValueSource = CdlValueSource_Current) const;
4030
    bool                has_integer_value( CdlValueSource = CdlValueSource_Current) const;
4031
    cdl_int             get_integer_value( CdlValueSource = CdlValueSource_Current) const;
4032
    bool                has_double_value(  CdlValueSource = CdlValueSource_Current) const;
4033
    double              get_double_value(  CdlValueSource = CdlValueSource_Current) const;
4034
    CdlSimpleValue      get_simple_value(  CdlValueSource = CdlValueSource_Current) const;
4035
 
4036
    CdlValueSource      get_source(CdlTransaction) const;
4037
    bool                has_source(        CdlTransaction, CdlValueSource) const;
4038
    bool                is_enabled(        CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4039
    std::string         get_value(         CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4040
    bool                has_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4041
    cdl_int             get_integer_value( CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4042
    bool                has_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4043
    double              get_double_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4044
    CdlSimpleValue      get_simple_value(  CdlTransaction, CdlValueSource = CdlValueSource_Current) const;
4045
 
4046
    // -----------------------------------------------------------------
4047
    // Modify access. There are two variants of all the functions:
4048
    //
4049
    // 1) no transaction argument. A transaction will be created,
4050
    //    committed, and destroyed for the change in question.
4051
    //
4052
    // 2) a transaction argument. The existing transaction will be
4053
    //    updated but not committed. This allows multiple changes
4054
    //    to be grouped together.
4055
    //
4056
    // There are only a handful of exported functions, but lots
4057
    // of inline variants.
4058
    void set_source(CdlValueSource);
4059
    void invalidate_source(CdlValueSource);
4060
    void set_enabled(bool, CdlValueSource);
4061
    void set_value(CdlSimpleValue&, CdlValueSource);
4062
    void set_enabled_and_value(bool, CdlSimpleValue&, CdlValueSource);
4063
    void set(CdlSimpleValue&, CdlValueSource);
4064
 
4065
    void set_source(CdlTransaction, CdlValueSource);
4066
    void invalidate_source(CdlTransaction, CdlValueSource);
4067
    void set_enabled(CdlTransaction, bool, CdlValueSource);
4068
    void set_value(CdlTransaction, CdlSimpleValue&, CdlValueSource);
4069
    void set_enabled_and_value(CdlTransaction, bool, CdlSimpleValue&, CdlValueSource);
4070
    void set(CdlTransaction, CdlSimpleValue&, CdlValueSource);
4071
    void set(CdlTransaction, const CdlValue&);
4072
 
4073
    void enable(CdlValueSource source)
4074
    {
4075
        set_enabled(true, source);
4076
    }
4077
    void disable(CdlValueSource source)
4078
    {
4079
        set_enabled(false, source);
4080
    }
4081
    void set_value(std::string data, CdlValueSource source)
4082
    {
4083
        CdlSimpleValue val(data);
4084
        set_value(val, source);
4085
    }
4086
    void set_integer_value(cdl_int data, CdlValueSource source)
4087
    {
4088
        CdlSimpleValue val(data);
4089
        set_value(val, source);
4090
    }
4091
    void set_double_value(double data, CdlValueSource source)
4092
    {
4093
        CdlSimpleValue val(data);
4094
        set_value(val, source);
4095
    }
4096
    void set_enabled_and_value(bool enabled, std::string data, CdlValueSource source)
4097
    {
4098
        CdlSimpleValue val(data);
4099
        set_enabled_and_value(enabled, val, source);
4100
    }
4101
    void set_enabled_and_value(bool enabled, cdl_int data, CdlValueSource source)
4102
    {
4103
        CdlSimpleValue val(data);
4104
        set_enabled_and_value(enabled, val, source);
4105
    }
4106
    void set_enabled_and_value(bool enabled, double data, CdlValueSource source)
4107
    {
4108
        CdlSimpleValue val(data);
4109
        set_enabled_and_value(enabled, val, source);
4110
    }
4111
    void enable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4112
    {
4113
        set_enabled_and_value(true, val, source);
4114
    }
4115
    void enable_and_set_value(std::string data, CdlValueSource source)
4116
    {
4117
        set_enabled_and_value(true, data, source);
4118
    }
4119
    void enable_and_set_value(cdl_int data, CdlValueSource source)
4120
    {
4121
        set_enabled_and_value(true, data, source);
4122
    }
4123
    void enable_and_set_value(double data, CdlValueSource source)
4124
    {
4125
        set_enabled_and_value(true, data, source);
4126
    }
4127
    void disable_and_set_value(CdlSimpleValue& val, CdlValueSource source)
4128
    {
4129
        set_enabled_and_value(false, val, source);
4130
    }
4131
    void disable_and_set_value(std::string data, CdlValueSource source)
4132
    {
4133
        set_enabled_and_value(false, data, source);
4134
    }
4135
    void disable_and_set_value(cdl_int data, CdlValueSource source)
4136
    {
4137
        set_enabled_and_value(false, data, source);
4138
    }
4139
    void disable_and_set_value(double data, CdlValueSource source)
4140
    {
4141
        set_enabled_and_value(false, data, source);
4142
    }
4143
    void enable(CdlTransaction transaction, CdlValueSource source)
4144
    {
4145
        set_enabled(transaction, true, source);
4146
    }
4147
    void disable(CdlTransaction transaction, CdlValueSource source)
4148
    {
4149
        set_enabled(transaction, false, source);
4150
    }
4151
    void set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4152
    {
4153
        CdlSimpleValue val(data);
4154
        set_value(transaction, val, source);
4155
    }
4156
    void set_integer_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4157
    {
4158
        CdlSimpleValue val(data);
4159
        set_value(transaction, val, source);
4160
    }
4161
    void set_double_value(CdlTransaction transaction, double data, CdlValueSource source)
4162
    {
4163
        CdlSimpleValue val(data);
4164
        set_value(transaction, val, source);
4165
    }
4166
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, std::string data, CdlValueSource source)
4167
    {
4168
        CdlSimpleValue val(data);
4169
        set_enabled_and_value(transaction, enabled, val, source);
4170
    }
4171
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, cdl_int data, CdlValueSource source)
4172
    {
4173
        CdlSimpleValue val(data);
4174
        set_enabled_and_value(transaction, enabled, val, source);
4175
    }
4176
    void set_enabled_and_value(CdlTransaction transaction, bool enabled, double data, CdlValueSource source)
4177
    {
4178
        CdlSimpleValue val(data);
4179
        set_enabled_and_value(transaction, enabled, val, source);
4180
    }
4181
    void enable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4182
    {
4183
        set_enabled_and_value(transaction, true, val, source);
4184
    }
4185
    void enable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4186
    {
4187
        set_enabled_and_value(transaction, true, data, source);
4188
    }
4189
    void enable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4190
    {
4191
        set_enabled_and_value(transaction, true, data, source);
4192
    }
4193
    void enable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4194
    {
4195
        set_enabled_and_value(transaction, true, data, source);
4196
    }
4197
    void disable_and_set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
4198
    {
4199
        set_enabled_and_value(transaction, false, val, source);
4200
    }
4201
    void disable_and_set_value(CdlTransaction transaction, std::string data, CdlValueSource source)
4202
    {
4203
        set_enabled_and_value(transaction, false, data, source);
4204
    }
4205
    void disable_and_set_value(CdlTransaction transaction, cdl_int data, CdlValueSource source)
4206
    {
4207
        set_enabled_and_value(transaction, false, data, source);
4208
    }
4209
    void disable_and_set_value(CdlTransaction transaction, double data, CdlValueSource source)
4210
    {
4211
        set_enabled_and_value(transaction, false, data, source);
4212
    }
4213
 
4214
    // -----------------------------------------------------------------
4215
    virtual bool   is_modifiable() const;
4216
    void           get_widget_hint(CdlWidgetHint&);
4217
 
4218
    // -----------------------------------------------------------------
4219
    // Propagation support. If a valuable becomes active or inactive
4220
    // because e.g. its parent is disabled then this may affect
4221
    // requires conflicts etc.
4222
    virtual void update(CdlTransaction, CdlUpdate);
4223
 
4224
    virtual bool test_active(CdlTransaction);
4225
 
4226
    // -----------------------------------------------------------------
4227
    // Property-related stuff.
4228
    bool                                has_calculated_expression() const;
4229
    bool                                has_default_value_expression() const;
4230
    bool                                has_legal_values() const;
4231
    bool                                has_entry_proc() const;
4232
    bool                                has_check_proc() const;
4233
    bool                                has_active_if_conditions() const;
4234
    bool                                has_requires_goals() const;
4235
    bool                                has_dialog() const;
4236
    bool                                has_wizard() const;
4237
 
4238
    CdlProperty_Expression              get_calculated_expression() const;
4239
    CdlProperty_Expression              get_default_value_expression() const;
4240
    CdlProperty_ListExpression          get_legal_values() const;
4241
    cdl_tcl_code                        get_entry_proc() const;
4242
    cdl_tcl_code                        get_check_proc() const;
4243
    void                                get_active_if_conditions(std::vector&) const;
4244
    void                                get_requires_goals(std::vector&) const;
4245
    CdlDialog                           get_dialog() const;
4246
    CdlWizard                           get_wizard() const;
4247
    void                                get_implemented_interfaces(std::vector&) const;
4248
 
4249
    // Add property parsers and validation code appropriate for a
4250
    // valuable object such as default_value and legal_values
4251
    static void         add_property_parsers(std::vector& parsers);
4252
    void                check_properties(CdlInterpreter);
4253
    static int          parse_active_if(CdlInterpreter, int, const char*[]);
4254
    static void         active_if_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4255
    static int          parse_calculated(CdlInterpreter, int, const char*[]);
4256
    static void         calculated_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4257
    static int          parse_check_proc(CdlInterpreter, int, const char*[]);
4258
    static int          parse_default_value(CdlInterpreter, int, const char*[]);
4259
    static void         default_value_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4260
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
4261
    static void         dialog_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4262
    static int          parse_entry_proc(CdlInterpreter, int, const char*[]);
4263
    static int          parse_flavor(CdlInterpreter, int, const char*[]);
4264
    static int          parse_group(CdlInterpreter, int, const char*[]);
4265
    static int          parse_implements(CdlInterpreter, int, const char*[]);
4266
    static void         implements_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4267
    static int          parse_legal_values(CdlInterpreter, int, const char*[]);
4268
    static void         legal_values_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4269
    static int          parse_requires(CdlInterpreter, int, const char*[]);
4270
    static void         requires_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4271
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
4272
    static void         wizard_update_handler(CdlTransaction, CdlNode, CdlProperty, CdlNode, CdlUpdate);
4273
 
4274
    // Persistence suppot
4275
    void save_valuable(CdlInterpreter, Tcl_Channel, int, bool /* modifiable */, bool /* minimal */);
4276
    bool value_savefile_entry_needed() const;
4277
    static void initialize_savefile_support(CdlToplevel, std::string);
4278
    static int  savefile_value_source_command(CdlInterpreter, int, const char*[]);
4279
    static int  savefile_user_value_command(CdlInterpreter, int, const char*[]);
4280
    static int  savefile_wizard_value_command(CdlInterpreter, int, const char*[]);
4281
    static int  savefile_inferred_value_command(CdlInterpreter, int, const char*[]);
4282
    static int  savefile_xxx_value_command(CdlInterpreter, int, const char*[], CdlValueSource);
4283
 
4284
    // Make sure that the current value is legal. This gets called automatically
4285
    // by all the members that modify values. It has to be a virtual function
4286
    // since some derived classes, e.g. hardware-related valuables, may impose
4287
    // constraints over and above legal_values etc.
4288
    virtual void check_value(CdlTransaction);
4289
 
4290
    // Similarly check the requires properties
4291
    void check_requires(CdlTransaction, CdlProperty_GoalExpression);
4292
    void check_requires(CdlTransaction);
4293
 
4294
    // Enabling or disabling a valuable may affect the active state of children
4295
    void check_children_active(CdlTransaction);
4296
 
4297
    virtual std::string get_class_name() const;
4298
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
4299
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
4300
 
4301
  protected:
4302
    CdlValuableBody(CdlValueFlavor = CdlValueFlavor_Bool);
4303
 
4304
 
4305
  private:
4306
 
4307
 
4308
    enum {
4309
        CdlValuableBody_Invalid = 0,
4310
        CdlValuableBody_Magic   = 0x2b2acc03
4311
    } cdlvaluablebody_cookie;
4312
 
4313
    // Illegal operations
4314
    CdlValuableBody(const CdlValuableBody&);
4315
    CdlValuableBody& operator=(const CdlValuableBody&);
4316
};
4317
 
4318
//}}}
4319
//{{{  CdlTransaction etc.
4320
 
4321
//{{{  Description
4322
 
4323
// ----------------------------------------------------------------------------
4324
// Transactions. These are used for all changes to a configuration. In some
4325
// cases a transaction is implicit:
4326
//
4327
//    valuable->set_value(...)
4328
//
4329
// The actual implementation of this is:
4330
//
4331
//    valuable->set_value(...)
4332
//        transact = CdlTransactionBody::make(valuable->get_toplevel())
4333
//        valuable->set_value(transact, ...)
4334
//        
4335
//        transact->commit()
4336
//        delete transact
4337
//
4338
// Alternatively the use of transactions may be explicit. For implicit
4339
// uses the library will invoke an inference callback at the
4340
// appropriate time. For explicit transactions this is not necessary.
4341
//
4342
// The commit() operation invokes a transaction callback which should
4343
// not be confused with the inference callback. The former is intended
4344
// for display updates, it specifies everything that has changed
4345
// during the transaction. The latter is used for reporting new
4346
// conflicts to the user, suggesting fixes, etc.
4347
//
4348
// A whole bunch of information is associated with a transaction,
4349
// including: all value changes, details of new conflicts, and details
4350
// of existing conflicts that have gone away. The commit operation
4351
// takes care of updating the toplevel. Until the commit happens
4352
// the toplevel itself remains unchanged. It is also possible to cancel
4353
// a transaction.
4354
//
4355
// An important concept related to transactions is propagation.
4356
// Changing a value may have various effects, for example it may
4357
// change the result of a legal_values list expression, resulting in a
4358
// conflict object having to be created or destroyed. Changing one
4359
// value may result in other value changes, e.g. because of a
4360
// default_value property. All this is "propagation", and may
4361
// happen multiple times within a single transaction.
4362
//
4363
// Transaction objects are also used during load or unload operations,
4364
// but those are a little bit special. In particular it is not possible
4365
// to cancel such a transaction, there will have been updates to the
4366
// toplevel. Using a transaction is convenient because there is a
4367
// need for propagation.
4368
//
4369
// Currently a transaction should be deleted immediately after a
4370
// commit or cancel. This may change in future, in that transaction
4371
// objects can be used to hold undo information.
4372
//
4373
//
4374
// The other big concept related to transactions is inference.
4375
// Changing a value may result in one or more new conflicts being
4376
// created. In some cases the library can figure out for itself how to
4377
// resolve these conflicts, using an inference engine. There are
4378
// parameters to control the operation of the inference engine,
4379
// including whether it runs at all, what changes it is allowed
4380
// to make automatically (usually default and inferred values can
4381
// be updated, but not wizard or user values), and how much
4382
// recursion will happen.
4383
//
4384
// Assuming a default setup in a GUI environment, a typical
4385
// sequence of events would be:
4386
//
4387
//     valuable->set_value(...)
4388
//         transact = CdlTransactionBody::make(valuable->get_toplevel())
4389
//         valuable->set_value(transact, ...)
4390
//             transact->set_whole_value(valuable, ...)
4391
//         transact->propagate()
4392
//         while (!finished)
4393
//             transact->resolve()
4394
//                 
4395
//             invoke inference callback
4396
//                 transact->apply_solution() (1 or more times)
4397
//                     transact->set_whole_value(valuable, ...) (1 or more times)
4398
//             transact->propagate()
4399
//         transact->commit() | transact->cancel()
4400
//         delete transact
4401
//
4402
// Note that the propagation steps have to be invoked explicitly,
4403
// allowing multiple changes to be processed in one go. There is
4404
// a utility function which combines the functionality from
4405
// the first propagate() call up to but not including the
4406
// transaction delete operator.
4407
//
4408
//
4409
// The inference engine itself is a complicated beast. There are
4410
// a number of interfaces, but at the end of the day it ends up
4411
// creating a sub-transaction and trying to resolve a single
4412
// conflict in that sub-transaction. The conflict may belong to
4413
// the current transaction or it may be global.
4414
//
4415
//     
4416
//         for each conflict of interest
4417
//             make sure that there is not already a valid solution
4418
//             check that the inference engine can handle it
4419
//             create a sub-transaction, associated with the conflict
4420
//             apply the conflict resolution code
4421
//             if the solution is ok
4422
//                 install it
4423
//             else if the solution might e.g. overwrite a user value
4424
//                 keep it, the user can decide during the inference callback
4425
//
4426
// The conflict resolution typically works by attempting to change
4427
// one or more values in the sub-transaction, propagating them,
4428
// and seeing what new conflicts get created. If no new conflicts
4429
// get created and one or more existing conflicts go away, groovy.
4430
// Otherwise recursion can be used to try to resolve the new
4431
// conflicts, or other strategies can be explored.
4432
//
4433
// NOTE: what is really necessary is some way of keeping track of the
4434
// "best" solution to date, and allow exploration of alternatives.
4435
// Or possibly keep track of all solutions. That has to be left to
4436
// a future version.
4437
 
4438
//}}}
4439
//{{{  CdlTransactionCommitCancelOp
4440
 
4441
// ----------------------------------------------------------------------------
4442
// The CdlTransaction class has built-in knowledge of how to handle values,
4443
// active state, and a few things like that. However there are also more
4444
// complicated operations such as loading and unloading, instantiating
4445
// items, etc. which also need to happen in the context of a transaction
4446
// but which the transaction class does not necessarily know about
4447
// itself - or at least, not in any detail. Since the libcdl core is
4448
// intended to be useful in various contexts, some sort of extensibility
4449
// is essential.
4450
//
4451
// This is achieved by an auxiliary class, CdlTransactionCommitCancelOp.
4452
// Clients of the transaction class can have their own utility class
4453
// which derives from this, and create suitable objects. The transaction
4454
// class maintains a vector of the pending commit/cancel operations.
4455
//
4456
// Each CdlTransactionCommitCancelOp object has two member functions,
4457
// one for when the transaction gets committed and one for when it
4458
// gets cancelled. If a sub-transaction gets committed then its
4459
// pending ops are transferred across to the parent, allowing the
4460
// parent to be cancelled sensibly: the commit ops only get run for
4461
// the toplevel transaction. If a sub-transaction gets cancelled then
4462
// the pending ops are invoked immediately.
4463
//
4464
// There is an assumption that commit/cancel ops get executed strictly
4465
// in FIFO order. Specifically, commit ops get run from first one to
4466
// the last one, allowing later operations in the transaction to
4467
// overwrite earlier ones. Cancel ops get run in reverse order.
4468
 
4469
class CdlTransactionCommitCancelOp {
4470
    friend class CdlTest;
4471
 
4472
  public:
4473
 
4474
    CdlTransactionCommitCancelOp() { }
4475
    virtual ~CdlTransactionCommitCancelOp() { };
4476
 
4477
    // The default implementations of both of these do nothing.
4478
    // Derived classes should override at least one of these
4479
    // functions.
4480
    virtual void commit(CdlTransaction transaction) {
4481
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
4482
    }
4483
    virtual void cancel(CdlTransaction transaction) {
4484
        CYG_UNUSED_PARAM(CdlTransaction, transaction);
4485
    }
4486
 
4487
  protected:
4488
 
4489
  private:
4490
};
4491
 
4492
//}}}
4493
//{{{  CdlTransaction class
4494
 
4495
class CdlTransactionBody {
4496
 
4497
    friend class CdlTest;
4498
 
4499
    friend class CdlConflictBody;
4500
    friend class CdlValuableBody;
4501
 
4502
  public:
4503
 
4504
    // Create a toplevel transaction
4505
    static CdlTransaction make(CdlToplevel);
4506
    virtual ~CdlTransactionBody();
4507
    CdlToplevel get_toplevel() const;
4508
 
4509
    // Or a sub-transaction. Usually these are created in the context of
4510
    // a conflict that is being resolved.
4511
    CdlTransaction make(CdlConflict = 0);
4512
    CdlTransaction get_parent() const;
4513
    CdlConflict    get_conflict() const;
4514
 
4515
    // Commit all the changes. Essentially this means transferring
4516
    // all of the per-transaction data to the toplevel, and then
4517
    // invoking the transaction callback. All propagation, inference,
4518
    // etc. should happen before the commit()
4519
    // This routine can also be used to transfer changes from a
4520
    // sub-transaction to the parent.
4521
    void        commit();
4522
 
4523
    // A variant of the commit() operation can be used to
4524
    // store a sub-transaction in a conflict's solution vector,
4525
    // rather than updating the parent transaction. This is useful
4526
    // for inferred solutions which cannot be applied without
4527
    // user confirmation
4528
    void        save_solution();
4529
 
4530
    // Can a solution held in a sub-transaction be applied without
4531
    // e.g. overwriting a user value with an inferred value?
4532
    bool        user_confirmation_required() const;
4533
 
4534
    // If the user has explicitly changed a value in the current transaction
4535
    // then the inference engine should not undo this or suggest a solution
4536
    // that will undo the change.
4537
    bool        changed_by_user(CdlValuable) const;
4538
 
4539
    // A variant which is used for checking the hierarchy when disabling
4540
    // a container
4541
    bool        subnode_changed_by_user(CdlContainer) const;
4542
 
4543
    // Is one transaction preferable to another?
4544
    bool        is_preferable_to(CdlTransaction) const;
4545
 
4546
    // Find out about per-transaction conflicts. This is particularly
4547
    // useful for the inference callback. The other containers can
4548
    // be accessed as well, for completeness.
4549
    const std::list&       get_new_conflicts() const;
4550
    const std::list&       get_new_structural_conflicts() const;
4551
    const std::vector&     get_deleted_conflicts() const;
4552
    const std::vector&     get_deleted_structural_conflicts() const;
4553
    const std::vector&     get_resolved_conflicts() const ;
4554
    const std::list&       get_global_conflicts_with_solutions() const;
4555
    const std::map& get_changes() const;
4556
    const std::set&            get_activated() const;
4557
    const std::set&            get_deactivated() const;
4558
    const std::set&        get_legal_values_changes() const;
4559
 
4560
    // Manipulate the current set of conflicts, allowing for nested
4561
    // transactions and toplevel conflicts as well.
4562
    void        clear_conflict(CdlConflict);
4563
    bool        has_conflict_been_cleared(CdlConflict);
4564
 
4565
    bool        has_conflict(CdlNode, bool (*)(CdlConflict));
4566
    CdlConflict get_conflict(CdlNode, bool (*)(CdlConflict));
4567
    void        get_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
4568
    void        clear_conflicts(CdlNode, bool (*)(CdlConflict));
4569
    bool        has_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4570
    CdlConflict get_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4571
    void        get_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
4572
    void        clear_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
4573
 
4574
    bool        has_structural_conflict(CdlNode, bool (*)(CdlConflict));
4575
    CdlConflict get_structural_conflict(CdlNode, bool (*)(CdlConflict));
4576
    void        get_structural_conflicts(CdlNode, bool (*)(CdlConflict), std::vector&);
4577
    void        clear_structural_conflicts(CdlNode, bool (*)(CdlConflict));
4578
    bool        has_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4579
    CdlConflict get_structural_conflict(CdlNode, CdlProperty, bool (*)(CdlConflict));
4580
    void        get_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict), std::vector&);
4581
    void        clear_structural_conflicts(CdlNode, CdlProperty, bool (*)(CdlConflict));
4582
 
4583
    // During the inference callback the user may decide to
4584
    // apply one or more of the solutions.
4585
    void        apply_solution(CdlConflict);
4586
    void        apply_solutions(const std::vector&);
4587
    void        apply_all_solutions();
4588
 
4589
    // Cancel all the changes done in this transaction. Essentially
4590
    // this just involves clearing out all the STL containers.
4591
    void        cancel();
4592
 
4593
    // Support for commit/cancel ops. These are used for
4594
    // e.g. load and unload operations.
4595
    void        add_commit_cancel_op(CdlTransactionCommitCancelOp *);
4596
    void        cancel_last_commit_cancel_op();
4597
    CdlTransactionCommitCancelOp* get_last_commit_cancel_op() const;
4598
    const std::vector& get_commit_cancel_ops() const;
4599
 
4600
    // Propagation support
4601
    void        add_active_change(CdlNode);
4602
    void        add_legal_values_change(CdlValuable);
4603
    void        propagate();
4604
    bool        is_propagation_required() const;
4605
 
4606
    // Inference engine support.
4607
    void        resolve(int = 0); // Process the new conflicts raised by this transaction
4608
    void        resolve(CdlConflict, int = 0);
4609
    void        resolve(const std::vector&, int = 0);
4610
 
4611
    // An auxiliary function called by the inference engine to perform recursion
4612
    bool        resolve_recursion(int);
4613
 
4614
    // This function combines propagation, inference, and commit
4615
    // in one easy-to-use package
4616
    void        body();
4617
 
4618
    // Changes.
4619
    // There is a call to get hold of a CdlValue reference. Modifications
4620
    // should happen via a sequence of the form:
4621
    //
4622
    //    valuable->set_value(transact, ...)
4623
    //        const CdlValue& old_value = transact->get_whole_value(CdlValuable);
4624
    //        CdlValue new_value = old_value;
4625
    //        
4626
    //        transact->set_whole_value(CdlValuable, old_value, new_value);
4627
    //
4628
    // When appropriate the get_whole_value() call takes care of
4629
    // updating the current conflict's solution_references vector. The
4630
    // set_whole_value() call updated the per-transaction changes map,
4631
    // and also stores sufficient information to support propagation.
4632
    // set_whole_value() requires both the old and new values, so
4633
    // that propagation can be optimized.
4634
    const CdlValue&     get_whole_value(CdlConstValuable) const;
4635
    void                set_whole_value(CdlValuable, const CdlValue&, const CdlValue&);
4636
 
4637
    // Control over active vs. inactive also needs to happen inside
4638
    // transactions
4639
    bool                is_active(CdlNode) const;
4640
    void                set_active(CdlNode, bool);
4641
 
4642
    // Callback and parameter settings
4643
    static void (*get_callback_fn())(const CdlTransactionCallback&);
4644
    static void                 set_callback_fn(void (*)(const CdlTransactionCallback&));
4645
    static void                 set_inference_callback_fn(CdlInferenceCallback);
4646
    static CdlInferenceCallback get_inference_callback_fn();
4647
    static void                 enable_automatic_inference();
4648
    static void                 disable_automatic_inference();
4649
    static bool                 is_automatic_inference_enabled();
4650
    static void                 set_inference_recursion_limit(int);
4651
    static int                  get_inference_recursion_limit();
4652
    // The override indicates the highest level of value source that the
4653
    // library can overwrite without needing user confirmation. The
4654
    // default value is CdlValueSource_Inferred, indicating that the
4655
    // library can overwrite default and inferred values but not
4656
    // wizard or user values.
4657
    static void                 set_inference_override(CdlValueSource);
4658
    static CdlValueSource       get_inference_override();
4659
 
4660
    bool        check_this(cyg_assert_class_zeal = cyg_quick) const;
4661
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
4662
 
4663
  protected:
4664
 
4665
  private:
4666
 
4667
    CdlTransactionBody(CdlToplevel, CdlTransaction, CdlConflict);
4668
 
4669
    // The associated toplevel and optionally the parent transaction
4670
    // and the conflict being worked on
4671
    CdlToplevel         toplevel;
4672
    CdlTransaction      parent;
4673
    CdlConflict         conflict;
4674
 
4675
    // Per-transaction information. All value changes, new conflicts
4676
    // etc. first live in the context of a transaction. The global
4677
    // configuration only gets updated if the transaction is commited.
4678
    // There is also a vector of the pending commit/cancel ops.
4679
    std::vector commit_cancel_ops;
4680
    std::map changes;
4681
    std::list          new_conflicts;
4682
    std::list          new_structural_conflicts;
4683
    std::vector        deleted_conflicts;  // Existing global ones
4684
    std::vector        deleted_structural_conflicts;
4685
    std::vector        resolved_conflicts; // New ones already fixed by the inference engine
4686
    std::list          global_conflicts_with_solutions;
4687
    std::set               activated;
4688
    std::set               deactivated;
4689
    std::set           legal_values_changes;
4690
    bool                            dirty;
4691
 
4692
    // Change propagation. It is necessary to keep track of all
4693
    // pending value changes, active changes, and of things being
4694
    // loaded or unloaded. The set_value() call is used to update the
4695
    // value_changes container.
4696
    std::deque     value_changes;
4697
    std::deque         active_changes;
4698
 
4699
 
4700
    // Control over the inference engine etc.
4701
    static CdlInferenceCallback inference_callback;
4702
    static bool                 inference_enabled;
4703
    static int                  inference_recursion_limit;
4704
    static CdlValueSource       inference_override;
4705
    static void (*callback_fn)(const CdlTransactionCallback&);
4706
 
4707
    enum {
4708
        CdlTransactionBody_Invalid = 0,
4709
        CdlTransactionBody_Magic   = 0x3f91e4df
4710
    } cdltransactionbody_cookie;
4711
 
4712
    // Illegal operations
4713
    CdlTransactionBody();
4714
    CdlTransactionBody(const CdlTransactionBody &);
4715
    CdlTransactionBody& operator=(const CdlTransactionBody&);
4716
};
4717
 
4718
//}}}
4719
//{{{  CdlTransactionCallback
4720
 
4721
// ----------------------------------------------------------------------------
4722
// The callback class is used to inform applications about all the
4723
// changes that are happening, including side effects. Application
4724
// code can install a callback function which gets invoked at the
4725
// end of every transaction.
4726
//
4727
// NOTE: this implementation is preliminary. In particular it is
4728
// not extensible, it only deals with changes relevant to software
4729
// configurations.
4730
 
4731
class CdlTransactionCallback {
4732
 
4733
    friend class CdlTest;
4734
    friend class CdlTransactionBody;
4735
 
4736
  public:
4737
    ~CdlTransactionCallback();
4738
    static void (*get_callback_fn())(const CdlTransactionCallback&);
4739
    static void set_callback_fn(void (*)(const CdlTransactionCallback&));
4740
 
4741
    // Callback functions should be able to retrieve information
4742
    // about the current transaction and toplevel, to avoid the use
4743
    // of statics.
4744
    CdlTransaction              get_transaction() const;
4745
    CdlToplevel                 get_toplevel() const;
4746
 
4747
    // active_changes and legal_values_changes get updated as the
4748
    // transaction proceeds, so a set implementation is more
4749
    // efficient. The others get filled in during a commit operation.
4750
    // A transaction may result in multiple conflicts for a given node
4751
    // being eliminated, so again a set is appropriate. For the others
4752
    // there is no possibility of duplicates so a vector is better.
4753
    std::vector    value_changes;
4754
    std::vector        active_changes;
4755
    std::vector    legal_values_changes;
4756
    std::vector    value_source_changes;
4757
    std::vector    new_conflicts;
4758
    std::vector    new_structural_conflicts;
4759
    std::vector        nodes_with_resolved_conflicts;
4760
    std::vector        nodes_with_resolved_structural_conflicts;
4761
 
4762
    bool check_this(cyg_assert_class_zeal = cyg_quick) const;
4763
 
4764
  protected:
4765
 
4766
  private:
4767
    CdlTransactionCallback(CdlTransaction);
4768
    CdlTransaction      transact;
4769
 
4770
    // Illegal operation.
4771
    CdlTransactionCallback();
4772
 
4773
    enum {
4774
        CdlTransactionCallback_Invalid     = 0,
4775
        CdlTransactionCallback_Magic       = 0x0cec3a95
4776
    } cdltransactioncallback_cookie;
4777
};
4778
 
4779
//}}}
4780
//{{{  CdlLocalTransaction
4781
 
4782
// ----------------------------------------------------------------------------
4783
// A utility class to create a per-function transaction object which gets
4784
// cleaned up automatically should an exception happen.
4785
 
4786
class CdlLocalTransaction {
4787
 
4788
    friend class CdlTrest;
4789
 
4790
  public:
4791
    CdlLocalTransaction(CdlToplevel toplevel) {
4792
        transaction = CdlTransactionBody::make(toplevel);
4793
    }
4794
    ~CdlLocalTransaction() {
4795
        // The destructor may get invoked during exception handling.
4796
        // It is assumed that cancelling the transaction would be a
4797
        // good thing when that happens. Normal operation should
4798
        // go through the body() or commit() members, which clear
4799
        // the transaction field.
4800
        // There is a slight consistency here. Normally after a
4801
        // transaction commit the transaction object is still
4802
        // around. Here the transaction object get deleted. This
4803
        // is unlikely to matter in practice.
4804
        if (0 != transaction) {
4805
            transaction->cancel();
4806
            delete transaction;
4807
        }
4808
    }
4809
    CdlTransaction get() {
4810
        return transaction;
4811
    }
4812
    void body() {
4813
        transaction->body();
4814
        delete transaction;
4815
        transaction = 0;
4816
    }
4817
    void commit() {
4818
        transaction->commit();
4819
        delete transaction;
4820
        transaction = 0;
4821
    }
4822
    void propagate() {
4823
        transaction->propagate();
4824
    }
4825
    void destroy() {
4826
        if (0 != transaction) {
4827
            transaction->cancel();
4828
            delete transaction;
4829
            transaction = 0;
4830
        }
4831
    }
4832
 
4833
  private:
4834
    CdlTransaction transaction;
4835
    CdlLocalTransaction();
4836
};
4837
 
4838
//}}}
4839
 
4840
//}}}
4841
//{{{  Build and define information
4842
 
4843
//{{{  Description
4844
 
4845
// ----------------------------------------------------------------------------
4846
// There are two related concepts: buildable components, and
4847
// definable components. The former typically refers to compiling
4848
// sources files to produce libraries, although other types of build
4849
// are possible. The latter refers to generating header files
4850
// containing the current configuration data. Typically any loadable
4851
// that is buildable is also definable, so that the source files can
4852
// #include the appropriate generated headers and adapt to the
4853
// configuration data that way. The inverse is not true: for example
4854
// in HCDL it may be appropriate to generate a header file but there
4855
// is nothing to be compiled, device drivers are software packages.
4856
//
4857
// The relevant base classes are as follows:
4858
//
4859
// 1) CdlBuildable      - this object can have build-related properties.
4860
//                        All buildables are also valuables.
4861
// 2) CdlBuildLoadable  - this is a base class for loadables, providing
4862
//                        some extra properties that are relevant for
4863
//                        loadables that can involve builds.
4864
// 3) CdlDefinable      - this object can result in #define's in a
4865
//                        header file. All exportables are also
4866
//                        valuables.
4867
// 4) CdlDefineLoadable - this is a base class for any loadables that
4868
//                        can contain buildables.
4869
//
4870
// Support for both buildable and exportable components is part of the
4871
// core library for now. This may change in future, depending on how
4872
// many CDL variants get implemented.
4873
//
4874
// There are various properties related to building. First, the
4875
// ones applicable to the CdlBuildLoadable class.
4876
//
4877
// 1) library xyz.
4878
//    This specifies the default library for anything built in this
4879
//    loadable. If there is no library property then it defaults to
4880
//    libtarget.a (or rather to a class static that happens to be
4881
//    initialized to libtarget.a)
4882
//
4883
// 2) include_dir .
4884
//    This specifies where the loadable's exported header files should
4885
//    end up. The default value is the toplevel, but e.g. the eCos
4886
//    kernel specifies an include_dir of cyg/kernel. Note that fixed
4887
//    header files are associated with buildables, not definables,
4888
//    the latter deal with generated header files only.
4889
//
4890
// 3) include_files 
4891
//    The recommended directory hierarchy for non-trivial packages
4892
//    involves separate subdirectories src, include, cdl, doc, and
4893
//    test. This is too heavyweight for very simple packages where it
4894
//    is better to keep everything in just one directory. However that
4895
//    introduces a potential conflict between public and private
4896
//    header files, which can be resolved by the include_files
4897
//    property. The actual rules are:
4898
//
4899
//    a) if there an include_files property, that lists all the
4900
//       headers that should be exported.
4901
//
4902
//    b) else if there is an include subdirectory, it is assumed that
4903
//       all files below that should be exported.
4904
//
4905
//    c) otherwise all files matching a suitable glob pattern should
4906
//       be exported. The default pattern is *.h *.hxx *.inl, but can
4907
//       be overwritten.
4908
//
4909
// 4) makefile 
4910
//    This allows component developers to provide a GNU makefile to be
4911
//    used for building, rather than specify the relevant information
4912
//    via properties.
4913
//    NOTE: this property is ignored for now. It is roughly
4914
//    equivalent to a custom build step where the command is
4915
//    "make -C  -f ", but in addition it is necessary to
4916
//    worry about phony targets for default, clean, etc.
4917
//
4918
// A DefineLoadable adds the following property:
4919
//
4920
// 1) define_header 
4921
//    This specifies the header file that will be generated. If this
4922
//    property is absent then the library will generate a default one
4923
//    based on the loadable's name, by discarding everything up to and
4924
//    including the first underscore, lowercasing the rest, and
4925
//    appending .h. For example, CYGPKG_KERNEL would result in a
4926
//    header file kernel.h.
4927
//
4928
//    Hardware packages have an implicit "define_header hardware.h"
4929
//    property.
4930
//
4931
// A buildable has the following properties:
4932
//
4933
// 1) compile [-library xyz]   ...
4934
//    This specifies one or more files that need to be compiled.
4935
//    By default the resulting object files will go into the
4936
//    current library (set via a higher-level library or
4937
//    defaulting to libtarget.a).
4938
//
4939
//    Legitimate filename suffixes for compile statements are .c, .cxx
4940
//    and .S. Further suffixes may be supported in future. In the
4941
//    long term we will need some external data files defining how
4942
//    the various suffixes should be handled.
4943
//
4944
//    Associated with every compilation are details of the compiler to
4945
//    be used and the compiler flags. For now no attempt is made
4946
//    to do anything interesting in this area, although there is
4947
//    sufficient information in the database for the needs of
4948
//    command line tools.
4949
//
4950
//    Longer term there are complications. Packages may want some
4951
//    control over the compiler flags that should be used, e.g.
4952
//    "requires {!(flags ~= ".*-fno-rtti.*")}" to guarantee that the
4953
//    compiler flags do not include -fno-rtti, rather useful if the
4954
//    package's source code depends on that language feature. Mixed
4955
//    architecture systems (e.g. ARM/Thumb) will cause problems when
4956
//    it comes to selecting the compiler. The exact means by which
4957
//    all this will work is not yet clear.
4958
//
4959
// 2) object [-library xyz]   ...
4960
//    This specifies one or more pre-built object files that should
4961
//    go into the appropriate library.
4962
//
4963
//    The problem here is coping with different architectures, and for
4964
//    many architectures it will also be necessary to worry about
4965
//    multilibs. Third party component vendors are unlikely to supply
4966
//    separate object files for every supported architecture and every
4967
//    valid multilib within those architectures, so there are
4968
//    constraints on the multilib-related compiler flags used for
4969
//    building other packages and the application itself.
4970
//
4971
//    NOTE: this property is ignored for now.
4972
//
4973
// 3) make_object [-library xyz] [-priority pri]  
4974
//
4975
//    For example:
4976
//
4977
//    make_object toyslock.o {
4978
//        toyslock.o : toyslock.y
4979
//                yacc toyslock.y
4980
//                $(CC) $(CFLAGS) -o toyslock.o y.tab.c
4981
//    }
4982
//
4983
//    This defines a custom build step for an object file that
4984
//    should go into a particular directory. A makefile syntax
4985
//    is used to define the rule simply because it is likely
4986
//    to be familiar to package developers, and does not
4987
//    imply that the builds will happen via a makefile.
4988
//
4989
//    The optional priority field indicates at which stage during
4990
//    the build the rule should trigger. The default value is
4991
//    100, which is the same as for all files specified in
4992
//    "compile" properties. A lower value means that the object
4993
//    will be generated earlier. Libraries are generated at
4994
//    priority 200, and "make" properties normally execute at
4995
//    priority 300.
4996
//    NOTE: it is not clear yet whether supporting priorities
4997
//    in this way is a good idea, or whether the dependencies
4998
//    information could be used instead.
4999
//
5000
//    Unresolved issues:
5001
//
5002
//    a) what commands can be used in the build rules? There
5003
//       should be a core set of supported commands, as per
5004
//       an eCos toolchain build. It should also be possible
5005
//       for packages to provide their own host tools.
5006
//
5007
//       For sourceware folks, moving away from a single toolchain
5008
//       tarball and expecting them to download and install
5009
//       egcs, binutils and gdb separately is actually a bad
5010
//       idea in this regard, it makes it much more likely that
5011
//       some users will have an incomplete tools installation and
5012
//       hence that builds will fail.
5013
//
5014
//    b) there is an obvious need for variable substitution in the
5015
//       rules, e.g. $(CC). At what stage do these variables get
5016
//       expanded, and where does the required information live?
5017
//
5018
//    c) who is responsible for header file dependency analysis?
5019
//       Should the rules be modified automatically to do this,
5020
//       or do we leave this to the package developer? It may be
5021
//       very hard to do the former, but the latter will cause
5022
//       problems for IDE integration.
5023
//
5024
//    d) in which directory will the rules get run? What prevents
5025
//       filename conflicts between different packages?
5026
//
5027
//    NOTE: make_object is not actually required just yet, but the
5028
//    issues are much the same as for the "make" property which is
5029
//    required.
5030
//
5031
// 4) make [-priority pri]  
5032
//
5033
//    For example:
5034
//
5035
//    make target.ld {
5036
//    target.ld : arm.ld
5037
//            $(CC) -E -P -xc $(CFLAGS) -o $@ $<
5038
//    }
5039
//
5040
//    This defines a custom build step for a target that is not going
5041
//    to end up in a library. The main such targets at the moment are
5042
//    the linker script, vectors.o, and extras.o, but there may well
5043
//    be others in future.
5044
//
5045
//    The default priority for "make" properties is 300, which means
5046
//    that the build rules trigger after all normal compilations and
5047
//    after the libraries are generated. It is possible to specify
5048
//    custom build steps that should run before any compilations
5049
//    using a priority < 100.
5050
//
5051
//    Unresolved issues:
5052
//
5053
//    a) what commands can be used?
5054
//
5055
//    b) variable substitution?
5056
//
5057
//    c) header file dependency analysis?
5058
//
5059
//    d) directories and filenames?
5060
//
5061
//    e) where should the resulting files end up? Currently they can
5062
//       all go into $(PREFIX)/lib, but in the long term we may
5063
//       need to be a bit more flexible.
5064
//
5065
// 5) build_proc 
5066
//
5067
//    This defines some Tcl code that should be run prior to any
5068
//    build, for example to generate a source file. It must run
5069
//    within the appropriate loadable's Tcl interpreter so that
5070
//    it can query the current configuration.
5071
//
5072
//    NOTE: this property is not implemented yet.
5073
//
5074
//
5075
// A definable has the following properties:
5076
//
5077
// 1) no_define
5078
//    Usually the library will generate either one or two #define's
5079
//    for every definable, inside the current header file. This can be
5080
//    suppressed by the no_define property, which is typically
5081
//    accompanied by some other #define-related property such as
5082
//    define_proc or define.
5083
//
5084
// 2) define [-file ] [-format ] symbol
5085
//    This will result in an additional #define for the specified
5086
//    symbol in the specified file. The only filenames that are valid
5087
//    are the loadable's current filename (as per define_header), and
5088
//    the global header file system.h. Use of the latter should be
5089
//    avoided.
5090
//
5091
//    The optional format string behaves as per the define_format
5092
//    property below.
5093
//
5094
// 3) define_format 
5095
//    This is only relevant for booldata or data flavors. By default
5096
//    two #define's will be generated (assuming the valuable is active
5097
//    and enabled):
5098
//
5099
//        #define  value
5100
//        #define _value
5101
//
5102
//    The latter will only be generated if the resulting symbol is
5103
//    a valid C preprocessor symbol, and is intended to allow the
5104
//    use of #ifdef as well as #ifdef (useful if the value is
5105
//    non-numerical).
5106
//
5107
//    The define_format property provides control over the first of
5108
//    these two #defines. The net result is that the #define will be
5109
//    generated by evaluating the following Tcl fragment:
5110
//
5111
//        set result "#define  [ ]"
5112
//
5113
//    Command and variable substitution are available if desired,
5114
//    but for anything that complicated the define_proc property
5115
//    is normally more useful.
5116
//
5117
//    define_format is only applicable to the default definition,
5118
//    so it cannot be used in conjunction with no_define. The
5119
//    define property supports a -format option.
5120
//
5121
// 4) define_proc 
5122
//    This specifies some Tcl code that should be run when header
5123
//    file generation takes place, in addition to any #define's
5124
//    generated by default or courtesy of define properties.
5125
//    The define_proc property is commonly used in conjunction with
5126
//    no_define, but this is not required.
5127
//
5128
//    There will be two channels already set up: cdl_header
5129
//    for the current loadable, and cdl_system_header for system.h.
5130
//    Writing data to system.h should be avoided.
5131
//
5132
// 5) if_define  
5133
 
5134
//    This property provides direct support for a common programming
5135
//    paradigm. It allows direct generation of code like the
5136
//    following:
5137
//
5138
//    #ifdef CYGSRC_TOYS_BLOCKS
5139
//    # define CYGDBG_INFRA_USE_PRECONDITIONS 1
5140
//    #endif
5141
//
5142
//    In this case CYGSRC_TOYS_BLOCKS is the condition and
5143
//    CYGDBG_INFRA_USE_PRECONDITIONS is the symbol. The
5144
//    #ifdef/#define sequence will be generated in addition to
5145
//    any other #define's resulting from the default behaviour,
5146
//    the define property, or the define_proc property. It is
5147
//    not affected by no_define.
5148
 
5149
//}}}
5150
//{{{  The build process
5151
 
5152
// ----------------------------------------------------------------------------
5153
// For command-line operation the steps involved in doing a build are:
5154
//
5155
// 1) work out what needs to be built.
5156
//
5157
// 2) generate a build and install tree. This involves making sure that
5158
//    the various directories exist and are accessible.
5159
//
5160
// 3) generate or update the toplevel makefile.
5161
//
5162
// 4) generate the configuration header files.
5163
//
5164
// For operation in an IDE steps (2) and (3) will be handled by
5165
// different code.
5166
//
5167
// There is a library call to get hold of all the build information:
5168
//
5169
//     config->get_build_info(CdlBuildInfo &info);
5170
//
5171
// This erases anything previously present in the build-info argument
5172
// and fills in the information appropriate to the current
5173
// configuration, essentially by walking down the list of loadables
5174
// and each loadable's list of nodes, checking for BuildLoadables
5175
// and Buildables along the way. The BuildInfo class is defined
5176
// further down.
5177
//
5178
// An alternative library call can be used to find out about all
5179
// possible files that need to be compiled etc., irrespective of the
5180
// current configuration settings. This could be useful when it
5181
// comes to letting the user control compiler flags etc.
5182
//
5183
//    config->get_all_build_info(CdlBuildInfo& info);
5184
//
5185
// There is another library call for step (4):
5186
//
5187
//    config->generate_config_headers(std::string directory)
5188
//
5189
// This will create or update the header files appropriate to
5190
// the current configuration. Temporary files will be generated,
5191
// diff'ed with the current version, and existing files will
5192
// only be modified if necessary. The directory argument
5193
// indicates where the header files should go, i.e. it should
5194
// be the equivalent of $(PREFIX)/include/pkgconf
5195
//
5196
// This library call does not delete any files it does not
5197
// recognize, that is the responsibility of higher-level code.
5198
// It is possible to get or update a list of the files that
5199
// will be generated:
5200
//
5201
//    config->get_config_headers(std::vector& headers)
5202
//
5203
// The argument will be cleared if necessary and then filled in with
5204
// the current set of header files. Higher level code can compare the
5205
// result with the current files in the directory and take or suggest
5206
// remedial action.
5207
//
5208
// There is also a library call which combines all four stages:
5209
//
5210
//    config->generate_build_tree(std::string build_tree, std::string prefix = $(BUILD)/install)
5211
//
5212
//
5213
// The order in which the various build steps happen is important.
5214
//
5215
// 1) non-configuration headers must be copied from the component
5216
//    repository into $(PREFIX)/include. No compiles can happen
5217
//    before this.
5218
//
5219
// 2) all compile properties can happen in parallel. These have an
5220
//    effective priority of 100.
5221
//
5222
// 3) all make_object priorities can happen in parallel with
5223
//    compiles. These have a default priority of 100, but the
5224
//    priority can be modified.
5225
//
5226
// 4) the generated objects and any pre-built objects should be
5227
//    incorporated into the appropriate library. This happens
5228
//    at priority 200.
5229
//
5230
// 5) custom build steps associated with "make" properties should
5231
//    now run. These have a default priority of 300, but it is
5232
//    possible to override this.
5233
//
5234
// Usually all source files will come from the component repository,
5235
// which means that they are read-only. Ideally it should also be
5236
// possible for a source file to be copied into the build tree and
5237
// edited there, and subsequent builds should pick up the copy rather
5238
// than the original. The build data generated by libcdl will always
5239
// be in the form of relative pathnames to facilitate this.
5240
 
5241
//}}}
5242
//{{{  CdlBuildInfo class
5243
 
5244
// ----------------------------------------------------------------------------
5245
// Extracting the build information.
5246
//
5247
// libcdl.a defines the following classes related to build information.
5248
//
5249
// CdlBuildInfo
5250
// CdlBuildInfo_Loadable
5251
// CdlBuildInfo_Header
5252
// CdlBuildInfo_Compile
5253
// CdlBuildInfo_Object
5254
// CdlBuildInfo_MakeObject
5255
// CdlBuildInfo_Make
5256
//
5257
// The build information is organized on a per-loadable basis.
5258
// Higher-level code may choose to flatten this or to keep the
5259
// distinction. A CdlBuildInfo object is primarily a vector of
5260
// CdlBuildInfo_Loadable objects. CdlBuildInfo objects can be created
5261
// statically.
5262
//
5263
// In turn, each CdlBuildInfo_Loadable object is primarily a
5264
// collection of five vectors, one each for Header, Compile, Object,
5265
// MakeObject and Make.
5266
//
5267
// All pathnames in these data structures will use forward slashes as
5268
// the directory separator, irrespective of the host platform. All
5269
// pathnames will be relative.
5270
 
5271
struct CdlBuildInfo_Header {
5272
    std::string         source;         /* include/cyg_ass.h    */
5273
    std::string         destination;    /* cyg/infra/cyg_ass.h  */
5274
};
5275
 
5276
struct CdlBuildInfo_Compile {
5277
    std::string         library;        /* libtarget.a          */
5278
    std::string         source;         /* src/fancy.cxx        */
5279
    // Compiler and cflags data may be added in future.
5280
};
5281
 
5282
struct CdlBuildInfo_Object {
5283
    std::string         library;        /* libtarget.a          */
5284
    std::string         object;         /* obj/hello.o          */
5285
};
5286
 
5287
struct CdlBuildInfo_MakeObject {
5288
    cdl_int             priority;       /* 100                  */
5289
    std::string         library;        /* libtarget.a          */
5290
    std::string         object;         /* toyslock.o           */
5291
    std::string         deps;           /* toyslock.y           */
5292
    /*
5293
      It is not clear whether the deps field is actually useful in the
5294
      context of IDE integration, but see the note about arm.inc
5295
      above.
5296
    */
5297
    std::string         rules;
5298
    /*
5299
      A typical value for "rules" might be:
5300
 
5301
        yacc toyslock.y
5302
        $(CC) $(CFLAGS) -o toyslock.o y.tab.c
5303
 
5304
      Leading white space is not significant. Newlines are significant.
5305
      Backslash escapes in the text will not have been processed yet.
5306
    */
5307
};
5308
 
5309
struct CdlBuildInfo_Make {
5310
    cdl_int             priority;       /* 300                  */
5311
    std::string         target;         /* extras.o             */
5312
    std::string         deps;           /* libextras.a          */
5313
    std::string         rules;
5314
    /*
5315
      Something like:
5316
 
5317
  $(CC) $(ARCHFLAGS) $(LDARCHFLAGS) -nostdlib -Wl,-r -Wl,--whole-archive $(PREFIX)/lib/libextras.a -o $(PREFIX)/lib/extras.o
5318
 
5319
    */
5320
};
5321
 
5322
class CdlBuildInfo_Loadable {
5323
 
5324
    friend class CdlTest;
5325
 
5326
  public:
5327
    std::string         name;           /* CYGPKG_INFRA         */
5328
    std::string         repository;     /* arbitrary path       */
5329
    std::string         directory;      /* infra/current        */
5330
    std::vector            headers;
5331
    std::vector           compiles;
5332
    std::vector            objects;
5333
    std::vector        make_objects;
5334
    std::vector              makes;
5335
 
5336
  protected:
5337
 
5338
  private:
5339
};
5340
 
5341
class CdlBuildInfo {
5342
 
5343
    friend class CdlTest;
5344
 
5345
  public:
5346
 
5347
    std::vector  entries;
5348
 
5349
  protected:
5350
 
5351
  private:
5352
};
5353
 
5354
//}}}
5355
//{{{  CdlBuildLoadable
5356
 
5357
// ----------------------------------------------------------------------------
5358
// BuildLoadables are derived from Loadables and are appropriate for
5359
// any loadables that can contain build information. There are a
5360
// number of properties applicable at this level: makefile,
5361
// include_dir, include_files and library. The main interface of
5362
// interest is update_build_info().
5363
//
5364
// It is likely that all BuildLoadables are also Buildables, but this
5365
// is not required.
5366
 
5367
class CdlBuildLoadableBody : virtual public CdlLoadableBody
5368
{
5369
    friend class CdlTest;
5370
 
5371
  public:
5372
    virtual ~CdlBuildLoadableBody();
5373
 
5374
    // This is the main way to extract information about what should
5375
    // get built. It takes into account the active and enabled states,
5376
    // as appropriate.
5377
    void        update_build_info(CdlBuildInfo&) const;
5378
 
5379
    // An alternative which ignores the active and enabled states.
5380
    void        update_all_build_info(CdlBuildInfo&) const;
5381
 
5382
    // Property parsers and validation code appropriate for a
5383
    // build-loadable object such as makefile
5384
    static void add_property_parsers(std::vector& parsers);
5385
    void        check_properties(CdlInterpreter);
5386
    static int  parse_library(CdlInterpreter, int, const char*[]);
5387
    static int  parse_makefile(CdlInterpreter, int, const char*[]);
5388
    static int  parse_include_dir(CdlInterpreter, int, const char*[]);
5389
    static int  parse_include_files(CdlInterpreter, int, const char*[]);
5390
 
5391
    // By default any compiled files will go into libtarget.a, which
5392
    // is the default value for this variable. Individual applications may
5393
    // specify an alternative default library.
5394
    static const char*  default_library_name;
5395
 
5396
    // When filling in a build_info structure the library needs to know
5397
    // what constitutes a header file. A glob pattern can be used for this.
5398
    // NOTE: in the long term this should come out of a data file.
5399
    static const char*  default_headers_glob_pattern;
5400
 
5401
    virtual std::string get_class_name() const;
5402
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5403
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5404
 
5405
  protected:
5406
    CdlBuildLoadableBody();
5407
 
5408
  private:
5409
 
5410
    enum {
5411
        CdlBuildLoadableBody_Invalid    = 0,
5412
        CdlBuildLoadableBody_Magic      = 0x55776643
5413
    } cdlbuildloadablebody_cookie;
5414
 
5415
    // Illegal operations
5416
    CdlBuildLoadableBody(const CdlBuildLoadableBody&);
5417
    CdlBuildLoadableBody& operator=(const CdlBuildLoadableBody&);
5418
};
5419
 
5420
//}}}
5421
//{{{  CdlBuildable
5422
 
5423
// ----------------------------------------------------------------------------
5424
// Buildable objects can have properties such as compile and
5425
// make_object. These properties are not normally accessed
5426
// directly. Instead there is a member function to update a
5427
// CdlBuildInfo_Loadable object.
5428
//
5429
// The build properties for a given buildable have an effect iff
5430
// that buildable is active, and in addition if the buildable is also
5431
// a valuable then it must be enabled.
5432
 
5433
class CdlBuildableBody : virtual public CdlNodeBody
5434
{
5435
 
5436
    friend class CdlTest;
5437
 
5438
  public:
5439
    virtual ~CdlBuildableBody();
5440
 
5441
    // This is the main way to extract information about what should
5442
    // get built. It takes into account the active and enabled states,
5443
    // as appropriate. The second argument indicates the default
5444
    // library for the current loadable.
5445
    void        update_build_info(CdlBuildInfo_Loadable&, std::string) const;
5446
 
5447
    // An alternative which ignores the active and enabled states.
5448
    void        update_all_build_info(CdlBuildInfo_Loadable&, std::string) const;
5449
 
5450
    // Add property parsers and validation code appropriate for a
5451
    // buildable object such as compile and make_object
5452
    static void add_property_parsers(std::vector& parsers);
5453
    void        check_properties(CdlInterpreter);
5454
 
5455
    static int  parse_build_proc(CdlInterpreter, int, const char*[]);
5456
    static int  parse_compile(CdlInterpreter, int, const char*[]);
5457
    static int  parse_make(CdlInterpreter, int, const char*[]);
5458
    static int  parse_make_object(CdlInterpreter, int, const char*[]);
5459
    static int  parse_object(CdlInterpreter, int, const char*[]);
5460
    static bool split_custom_build_step(std::string /* data */, std::string& /* target */, std::string& /* deps */,
5461
                                        std::string& /* rules*/, std::string& /* error_msg */);
5462
 
5463
    virtual std::string get_class_name() const;
5464
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5465
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5466
 
5467
  protected:
5468
    CdlBuildableBody();
5469
 
5470
  private:
5471
 
5472
    enum {
5473
        CdlBuildableBody_Invalid        = 0,
5474
        CdlBuildableBody_Magic          = 0x16eb1c04
5475
    } cdlbuildablebody_cookie;
5476
 
5477
    // Illegal operations
5478
    CdlBuildableBody(const CdlBuildableBody&);
5479
    CdlBuildableBody& operator=(const CdlBuildableBody&);
5480
};
5481
 
5482
//}}}
5483
//{{{  CdlDefineLoadable
5484
 
5485
// ----------------------------------------------------------------------------
5486
// DefineLoadables are derived from Loadables and are appropriate for
5487
// any loadables that can result in generated header files containing
5488
// configuration data. There is one applicable property,
5489
// define_header. The main interface of interest is
5490
// generate_config_headers().
5491
 
5492
class CdlDefineLoadableBody : virtual public CdlLoadableBody
5493
{
5494
 
5495
    friend class CdlTest;
5496
 
5497
  public:
5498
    virtual ~CdlDefineLoadableBody();
5499
 
5500
    // Update the header file for this loadable. The first argument
5501
    // is a channel to the loadable-specific header file. The second
5502
    // argument is a channel to the global header file.
5503
    void        generate_config_header(Tcl_Channel, Tcl_Channel) const;
5504
 
5505
    // What header file should be generated for this loadable?
5506
    virtual std::string get_config_header() const;
5507
 
5508
    // Add property parsers and validation code.
5509
    static void         add_property_parsers(std::vector& parsers);
5510
    void                check_properties(CdlInterpreter);
5511
    static int          parse_define_header(CdlInterpreter, int, const char*[]);
5512
 
5513
    virtual std::string get_class_name() const;
5514
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5515
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5516
 
5517
  protected:
5518
    CdlDefineLoadableBody();
5519
 
5520
  private:
5521
 
5522
    enum {
5523
        CdlDefineLoadableBody_Invalid   = 0,
5524
        CdlDefineLoadableBody_Magic     = 0x7e211709
5525
    } cdldefineloadablebody_cookie;
5526
 
5527
    // Illegal operations
5528
    CdlDefineLoadableBody(const CdlDefineLoadableBody&);
5529
    CdlDefineLoadableBody& operator=(const CdlDefineLoadableBody&);
5530
};
5531
 
5532
//}}}
5533
//{{{  CdlDefinable
5534
 
5535
// ----------------------------------------------------------------------------
5536
// Definables are derived from Valuables and provide support for
5537
// outputting a configuration header file.
5538
 
5539
class CdlDefinableBody : virtual public CdlValuableBody
5540
{
5541
 
5542
    friend class CdlTest;
5543
 
5544
  public:
5545
    virtual ~CdlDefinableBody();
5546
 
5547
    // Update the header file for this definable. The loadable's Tcl
5548
    // interpreter will already have channels cdl_header and
5549
    // cdl_system_header set up appropriately.
5550
    void        generate_config_header( Tcl_Channel, Tcl_Channel) const;
5551
 
5552
    // Add property parsers and validation code.
5553
    static void add_property_parsers(std::vector& parsers);
5554
    void        check_properties(CdlInterpreter);
5555
    static int  parse_define(CdlInterpreter, int, const char*[]);
5556
    static int  parse_define_format(CdlInterpreter, int, const char*[]);
5557
    static int  parse_define_proc(CdlInterpreter, int, const char*[]);
5558
    static int  parse_if_define(CdlInterpreter, int, const char*[]);
5559
    static int  parse_no_define(CdlInterpreter, int, const char*[]);
5560
 
5561
    virtual std::string get_class_name() const;
5562
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5563
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5564
 
5565
  protected:
5566
    CdlDefinableBody();
5567
 
5568
  private:
5569
 
5570
    enum {
5571
        CdlDefinableBody_Invalid        = 0,
5572
        CdlDefinableBody_Magic          = 0x65a2c95a
5573
    } cdldefinablebody_cookie;
5574
 
5575
    // Illegal operations
5576
    CdlDefinableBody(const CdlDefinableBody&);
5577
    CdlDefinableBody& operator=(const CdlDefinableBody&);
5578
};
5579
 
5580
//}}}
5581
 
5582
//}}}
5583
//{{{  CdlDialog
5584
 
5585
// ----------------------------------------------------------------------------
5586
// A dialog simply inherits from CdlUserVisible and provides convenient
5587
// access to several dialog-specific properties.
5588
 
5589
class CdlDialogBody :
5590
    public virtual CdlUserVisibleBody,
5591
    public virtual CdlParentableBody
5592
{
5593
    friend class CdlTest;
5594
 
5595
  public:
5596
 
5597
    virtual ~CdlDialogBody();
5598
 
5599
    // Dialogs may be enabled or disabled globally. This affects
5600
    // CdlValuable::get_widget_hint() if the valuable has an associated
5601
    // custom dialog.
5602
    static void         disable_dialogs();
5603
    static void         enable_dialogs();
5604
    static bool         dialogs_are_enabled();
5605
 
5606
    bool                has_init_proc() const;
5607
    bool                has_update_proc() const;
5608
    const cdl_tcl_code& get_init_proc() const;
5609
    const cdl_tcl_code& get_update_proc() const;
5610
    const cdl_tcl_code& get_display_proc() const;
5611
    const cdl_tcl_code& get_confirm_proc() const;
5612
    const cdl_tcl_code& get_cancel_proc() const;
5613
 
5614
    static int          parse_dialog(CdlInterpreter, int, const char*[]);
5615
    static int          parse_display_proc(CdlInterpreter, int, const char*[]);
5616
    static int          parse_update_proc(CdlInterpreter, int, const char*[]);
5617
 
5618
    // Persistence support. Dialogs should just be ignored when it
5619
    // comes to saving and restoring files.
5620
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
5621
 
5622
    virtual std::string get_class_name() const;
5623
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5624
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5625
 
5626
  private:
5627
    // The constructor only gets invoked from inside parse_dialog()
5628
    CdlDialogBody(std::string);
5629
 
5630
    static bool         dialogs_enabled;
5631
 
5632
    enum {
5633
        CdlDialogBody_Invalid   = 0,
5634
        CdlDialogBody_Magic     = 0x3f4df391
5635
    } cdldialogbody_cookie;
5636
 
5637
    // Illegal operations. The dialog name must be known at the time
5638
    // that the object is constructed.
5639
    CdlDialogBody();
5640
    CdlDialogBody(const CdlDialogBody&);
5641
    CdlDialogBody& operator=(const CdlDialogBody&);
5642
};
5643
 
5644
//}}}
5645
//{{{  CdlWizard
5646
 
5647
// ----------------------------------------------------------------------------
5648
// A wizard is very much like a dialog, just a different set of properties.
5649
 
5650
class CdlWizardBody :
5651
    public virtual CdlUserVisibleBody,
5652
    public virtual CdlParentableBody
5653
{
5654
    friend class CdlTest;
5655
 
5656
  public:
5657
 
5658
    virtual ~CdlWizardBody();
5659
 
5660
    bool                has_init_proc() const;
5661
    bool                has_decoration_proc() const;
5662
    const cdl_tcl_code& get_init_proc() const;
5663
    const cdl_tcl_code& get_decoration_proc() const;
5664
    const cdl_tcl_code& get_confirm_proc() const;
5665
    const cdl_tcl_code& get_cancel_proc() const;
5666
    bool                has_screen(cdl_int) const;
5667
    cdl_int             get_first_screen_number() const;
5668
    const cdl_tcl_code& get_first_screen() const;
5669
    const cdl_tcl_code& get_screen(cdl_int) const;
5670
    static int          parse_wizard(CdlInterpreter, int, const char*[]);
5671
    static int          parse_cancel_proc(CdlInterpreter, int, const char*[]);
5672
    static int          parse_confirm_proc(CdlInterpreter, int, const char*[]);
5673
    static int          parse_decoration_proc(CdlInterpreter, int, const char*[]);
5674
    static int          parse_init_proc(CdlInterpreter, int, const char*[]);
5675
    static int          parse_screen(CdlInterpreter, int, const char*[]);
5676
 
5677
    // Persistence support. Wizards should just be ignored when it
5678
    // comes to saving and restoring files.
5679
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
5680
 
5681
    virtual std::string get_class_name() const;
5682
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5683
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5684
 
5685
  private:
5686
    // The constructor only gets invoked from inside parse_wizard().
5687
    CdlWizardBody(std::string);
5688
 
5689
    // Illegal operations.
5690
    CdlWizardBody();
5691
    CdlWizardBody(const CdlWizardBody&);
5692
    CdlWizardBody& operator=(const CdlWizardBody&);
5693
 
5694
    enum {
5695
        CdlWizardBody_Invalid   = 0,
5696
        CdlWizardBody_Magic     = 0x4ec1c39a
5697
    } cdlwizardbody_cookie;
5698
};
5699
 
5700
//}}}
5701
//{{{  CdlInterface class
5702
 
5703
// ----------------------------------------------------------------------------
5704
// Similarly for interfaces.
5705
 
5706
class CdlInterfaceBody : public virtual CdlNodeBody,
5707
                         public virtual CdlUserVisibleBody,
5708
                         public virtual CdlValuableBody,
5709
                         public virtual CdlParentableBody,
5710
                         public virtual CdlBuildableBody,
5711
                         public virtual CdlDefinableBody
5712
{
5713
    friend class CdlTest;
5714
 
5715
  public:
5716
 
5717
    ~CdlInterfaceBody();
5718
 
5719
    void                get_implementers(std::vector&) const;
5720
    void                recalculate(CdlTransaction);
5721
 
5722
    static int          parse_interface(CdlInterpreter, int, const char*[]);
5723
 
5724
    // Persistence support. The interface data cannot sensibly be modified
5725
    // by users, it is all calculated. However it is useful to have the
5726
    // interface data present in the saved file so that users can examine
5727
    // dependencies etc.
5728
    virtual void        save(CdlInterpreter, Tcl_Channel, int, bool);
5729
    static void         initialize_savefile_support(CdlToplevel);
5730
    static int          savefile_interface_command(CdlInterpreter, int, const char*[]);
5731
 
5732
    bool                was_generated() const;
5733
    virtual bool        is_modifiable() const;
5734
    virtual std::string get_class_name() const;
5735
    bool                check_this(cyg_assert_class_zeal = cyg_quick) const;
5736
    CYGDBG_DECLARE_MEMLEAK_COUNTER();
5737
 
5738
  private:
5739
    CdlInterfaceBody(std::string, bool /* generated */);
5740
    bool        generated;
5741
 
5742
    enum {
5743
        CdlInterfaceBody_Invalid   = 0,
5744
        CdlInterfaceBody_Magic     = 0x67f7fbe5
5745
    } cdlinterfacebody_cookie;
5746
    CdlInterfaceBody();
5747
    CdlInterfaceBody(const CdlInterfaceBody&);
5748
    CdlInterfaceBody& operator=(const CdlInterfaceBody&);
5749
};
5750
 
5751
//}}}
5752
 
5753
#endif  /* !__CDLCORE_HXX */
5754
// EOF cdlcore.hxx

powered by: WebSVN 2.1.0

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