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
|