OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [cdlcore.hxx] - Blame information for rev 174

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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