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

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [tools/] [src/] [libcdl/] [value.cxx] - Blame information for rev 321

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

Line No. Rev Author Line
1 26 unneback
//{{{  Banner                           
2
 
3
//============================================================================
4
//
5
//      value.cxx
6
//
7
//      Implementation of value-related CDL classes.
8
//
9
//============================================================================
10
//####COPYRIGHTBEGIN####
11
//                                                                          
12
// ----------------------------------------------------------------------------
13
// Copyright (C) 2002 Bart Veer
14
// Copyright (C) 1999, 2000, 2001 Red Hat, Inc.
15
//
16
// This file is part of the eCos host tools.
17
//
18
// This program is free software; you can redistribute it and/or modify it 
19
// under the terms of the GNU General Public License as published by the Free 
20
// Software Foundation; either version 2 of the License, or (at your option) 
21
// any later version.
22
// 
23
// This program is distributed in the hope that it will be useful, but WITHOUT 
24
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
25
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
26
// more details.
27
// 
28
// You should have received a copy of the GNU General Public License along with
29
// this program; if not, write to the Free Software Foundation, Inc., 
30
// 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
31
//
32
// ----------------------------------------------------------------------------
33
//                                                                          
34
//####COPYRIGHTEND####
35
//============================================================================
36
//#####DESCRIPTIONBEGIN####
37
//
38
// Author(s):   bartv
39
// Contact(s):  bartv
40
// Date:        1999/07/12
41
// Version:     0.02
42
//
43
//####DESCRIPTIONEND####
44
//============================================================================
45
 
46
//}}}
47
//{{{  #include's                       
48
 
49
// ----------------------------------------------------------------------------
50
#include "cdlconfig.h"
51
 
52
// Get the infrastructure types, assertions, tracing and similar
53
// facilities.
54
#include <cyg/infra/cyg_ass.h>
55
#include <cyg/infra/cyg_trac.h>
56
 
57
// <cdlcore.hxx> defines everything implemented in this module.
58
// It implicitly supplies <string>, <vector> and <map> because
59
// the class definitions rely on these headers.
60
#include <cdlcore.hxx>
61
 
62
//}}}
63
 
64
//{{{  Statics                          
65
 
66
// ----------------------------------------------------------------------------
67
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValue);
68
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListValue);
69
CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValuableBody);
70
 
71
//}}}
72
//{{{  CdlSimpleValue class             
73
 
74
//{{{  Constructors                     
75
 
76
// ----------------------------------------------------------------------------
77
 
78
CdlSimpleValue::CdlSimpleValue()
79
{
80
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: default constructor");
81
    CYG_REPORT_FUNCARG1XV(this);
82
 
83
    value               = "0";
84
    int_value           = 0;
85
    double_value        = 0.0;
86
    valid_flags         = int_valid | double_valid | string_valid;
87
    format              = CdlValueFormat_Default;
88
 
89
    CYG_REPORT_RETURN();
90
}
91
 
92
CdlSimpleValue::CdlSimpleValue(std::string val)
93
{
94
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: string constructor");
95
    CYG_REPORT_FUNCARG1XV(this);
96
 
97
    value               = val;
98
    int_value           = 0;
99
    double_value        = 0.0;
100
    valid_flags         = string_valid;
101
    format              = CdlValueFormat_Default;
102
 
103
    CYG_REPORT_RETURN();
104
}
105
 
106
CdlSimpleValue::CdlSimpleValue(cdl_int val)
107
{
108
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: int constructor");
109
    CYG_REPORT_FUNCARG1XV(this);
110
 
111
    value               = "0";
112
    int_value           = val;
113
    double_value        = 0.0;
114
    valid_flags         = int_valid;
115
    format              = CdlValueFormat_Default;
116
 
117
    CYG_REPORT_RETURN();
118
}
119
 
120
CdlSimpleValue::CdlSimpleValue(double val)
121
{
122
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: double constructor");
123
    CYG_REPORT_FUNCARG1XV(this);
124
 
125
    value               = "0";
126
    int_value           = 0;
127
    double_value        = val;
128
    valid_flags         = double_valid;
129
    format              = CdlValueFormat_Default;
130
 
131
    CYG_REPORT_RETURN();
132
}
133
 
134
CdlSimpleValue::CdlSimpleValue(bool val)
135
{
136
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool constructor");
137
    CYG_REPORT_FUNCARG2XV(this, val);
138
 
139
    value               = (val) ? "1" : "0";
140
    int_value           = (val) ? 1 : 0;
141
    double_value        = 0.0;
142
    valid_flags         = string_valid | int_valid;
143
    format              = CdlValueFormat_Default;
144
 
145
    CYG_REPORT_RETURN();
146
}
147
 
148
CdlSimpleValue::CdlSimpleValue(const CdlSimpleValue& original)
149
{
150
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: copy constructor");
151
    CYG_REPORT_FUNCARG2XV(this, &original);
152
 
153
    value               = original.value;
154
    int_value           = original.int_value;
155
    double_value        = original.double_value;
156
    valid_flags         = original.valid_flags;
157
    format              = original.format;
158
 
159
    CYG_REPORT_RETURN();
160
}
161
 
162
//}}}
163
//{{{  Destructor                       
164
 
165
// ----------------------------------------------------------------------------
166
 
167
CdlSimpleValue::~CdlSimpleValue()
168
{
169
    CYG_REPORT_FUNCNAME("CdlsimpleValue:: destructor");
170
    CYG_REPORT_FUNCARG1XV(this);
171
 
172
    value               = "";
173
    int_value           = 0;
174
    double_value        = 0.0;
175
    valid_flags         = 0;
176
    format              = CdlValueFormat_Default;
177
 
178
    CYG_REPORT_RETURN();
179
}
180
 
181
//}}}
182
//{{{  Assignment operators             
183
 
184
// ----------------------------------------------------------------------------
185
 
186
CdlSimpleValue&
187
CdlSimpleValue::operator=(const CdlSimpleValue& original)
188
{
189
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: assignment operator");
190
    CYG_REPORT_FUNCARG2XV(this, &original);
191
 
192
    if (this != &original) {
193
        value           = original.value;
194
        int_value       = original.int_value;
195
        double_value    = original.double_value;
196
        valid_flags     = original.valid_flags;
197
        format          = original.format;
198
    }
199
 
200
    CYG_REPORT_RETURN();
201
    return *this;
202
}
203
 
204
CdlSimpleValue&
205
CdlSimpleValue::operator=(std::string val)
206
{
207
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: string assignment");
208
    CYG_REPORT_FUNCARG1XV(this);
209
 
210
    value               = val;
211
    int_value           = 0;
212
    double_value        = 0.0;
213
    valid_flags         = string_valid;
214
    format              = CdlValueFormat_Default;
215
 
216
    CYG_REPORT_RETURN();
217
    return *this;
218
}
219
 
220
CdlSimpleValue&
221
CdlSimpleValue::operator=(cdl_int val)
222
{
223
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: integer assignment");
224
    CYG_REPORT_FUNCARG1XV(this);
225
 
226
    value               = "";
227
    int_value           = val;
228
    double_value        = 0.0;
229
    valid_flags         = int_valid;
230
    format              = CdlValueFormat_Default;
231
 
232
    CYG_REPORT_RETURN();
233
    return *this;
234
}
235
 
236
CdlSimpleValue&
237
CdlSimpleValue::operator=(double val)
238
{
239
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: double assignment");
240
    CYG_REPORT_FUNCARG1XV(this);
241
 
242
    value               = "";
243
    int_value           = 0;
244
    double_value        = val;
245
    valid_flags         = double_valid;
246
    format              = CdlValueFormat_Default;
247
 
248
    CYG_REPORT_RETURN();
249
    return *this;
250
}
251
 
252
// ----------------------------------------------------------------------------
253
// Converting a boolean into a simple value. This is sufficiently common
254
// to warrant its own member function, and in addition it avoids
255
// ambiguity when assigning 0.
256
 
257
CdlSimpleValue&
258
CdlSimpleValue::operator=(bool val)
259
{
260
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool assignment");
261
    CYG_REPORT_FUNCARG1XV(this);
262
 
263
    value               = (val) ? "1" : "0";
264
    int_value           = (val) ? 1 : 0;
265
    double_value        = 0.0;
266
    valid_flags         = string_valid | int_valid;
267
    format              = CdlValueFormat_Default;
268
 
269
    CYG_REPORT_RETURN();
270
    return *this;
271
}
272
 
273
//}}}
274
//{{{  CdlValuable -> CdlSimpleValue    
275
 
276
// ----------------------------------------------------------------------------
277
// This routine bridges the gap between the full data held in the CdlValuable
278
// object and the basic information needed for expression evaluation.
279
 
280
void
281
CdlSimpleValue::eval_valuable(CdlEvalContext& context, CdlValuable valuable, CdlSimpleValue& result)
282
{
283
    CYG_REPORT_FUNCNAME("CdlSimpleValue:: valuable assignment");
284
    CYG_REPORT_FUNCARG3XV(&context, valuable, &result);
285
    CYG_PRECONDITION_CLASSC(valuable);
286
 
287
    // If the valuable is not currently active then its value is
288
    // always zero for the purposes of expression evaluation.
289
    // FIXME: this check should be on a per-transaction basis.
290
    if (((0 != context.transaction) && !context.transaction->is_active(valuable)) ||
291
        ((0 == context.transaction) && !valuable->is_active())) {
292
 
293
        result.value           = "0";
294
        result.int_value       = 0;
295
        result.double_value    = 0.0;
296
        result.valid_flags     = string_valid | int_valid;
297
        result.format          = CdlValueFormat_Default;
298
        CYG_REPORT_RETURN();
299
        return;
300
    }
301
 
302
    // Get hold of the underlying CdlValue object
303
    const CdlValue& val = (0 != context.transaction) ?
304
        context.transaction->get_whole_value(valuable) : valuable->get_whole_value();
305
 
306
    // Otherwise the value depends on the flavor.
307
    switch(val.get_flavor()) {
308
      case CdlValueFlavor_None :
309
      {
310
        // This could be treated as an error, but since valuables with flavor
311
        // none are permanently enabled a constant "1" is a better result.
312
        result.value           = "1";
313
        result.int_value       = 1;
314
        result.double_value    = 0.0;
315
        result.valid_flags     = string_valid | int_valid;
316
        result.format          = CdlValueFormat_Default;
317
        break;
318
      }
319
      case CdlValueFlavor_Bool :
320
      {
321
        bool enabled           = val.is_enabled();
322
        result.value           = (enabled) ? "1" : "0";
323
        result.int_value       = (enabled) ?  1  :  0;
324
        result.double_value    = 0.0;
325
        result.valid_flags     = string_valid | int_valid;
326
        result.format          = CdlValueFormat_Default;
327
        break;
328
      }
329
      case CdlValueFlavor_BoolData :
330
      {
331
        if (!val.is_enabled()) {
332
 
333
            result.value        = "0";
334
            result.int_value    = 0;
335
            result.double_value = 0.0;
336
            result.valid_flags  = string_valid | int_valid;
337
            result.format       = CdlValueFormat_Default;
338
 
339
        } else {
340
 
341
            // Just use a copy constructor, let the compiler optimise things.
342
            result = val.get_simple_value();
343
        }
344
        break;
345
      }
346
      case CdlValueFlavor_Data :
347
      {
348
        // Just like BoolData, but with no need to check the enabled flag.
349
        result = val.get_simple_value();
350
        break;
351
      }
352
      default:
353
      {
354
        CYG_FAIL("Valuable object with an unknown flavor encountered.");
355
      }
356
    }
357
 
358
    CYG_REPORT_RETURN();
359
}
360
 
361
//}}}
362
//{{{  Getting the value                
363
 
364
// ----------------------------------------------------------------------------
365
// Some of these calls involve conversion operators.
366
 
367
std::string
368
CdlSimpleValue::get_value() const
369
{
370
    CYG_REPORT_FUNCNAME("CdlSimpleValue::get_value");
371
    CYG_REPORT_FUNCARG1XV(this);
372
 
373
    if (!(valid_flags & string_valid)) {
374
        if (valid_flags & int_valid) {
375
            Cdl::integer_to_string(int_value, value, format);
376
        } else if (valid_flags & double_valid) {
377
            Cdl::double_to_string(double_value, value, format);
378
        } else {
379
            CYG_FAIL("Attempt to use uninitialized SimpleValue");
380
        }
381
        valid_flags |= string_valid;
382
    }
383
 
384
    CYG_REPORT_RETURN();
385
    return value;
386
}
387
 
388
bool
389
CdlSimpleValue::has_integer_value() const
390
{
391
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_integer_value", "result %d");
392
    CYG_REPORT_FUNCARG1XV(this);
393
 
394
    if (!(valid_flags & (int_valid | int_invalid))) {
395
        if (valid_flags & double_valid) {
396
            if (Cdl::double_to_integer(double_value, int_value)) {
397
                valid_flags |= int_valid;
398
            } else {
399
                valid_flags |= int_invalid;
400
            }
401
        } else if (valid_flags & string_valid) {
402
            if (Cdl::string_to_integer(value, int_value)) {
403
                valid_flags |= int_valid;
404
            } else {
405
                valid_flags |= int_invalid;
406
            }
407
        } else {
408
            CYG_FAIL("Attempt to use uninitialized SimpleValue");
409
        }
410
    }
411
 
412
    bool result = (valid_flags & int_valid);
413
    CYG_REPORT_RETVAL(result);
414
    return result;
415
}
416
 
417
cdl_int
418
CdlSimpleValue::get_integer_value() const
419
{
420
    CYG_REPORT_FUNCNAMETYPE("CdlsimpleValue::get_integer_value", "result %ld");
421
    CYG_REPORT_FUNCARG1XV(this);
422
 
423
    cdl_int result = 0;
424
    if ((valid_flags & int_valid) || has_integer_value()) {
425
        result = int_value;
426
    }
427
 
428
    CYG_REPORT_RETVAL((int) result);
429
    return result;
430
}
431
 
432
bool
433
CdlSimpleValue::has_double_value() const
434
{
435
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_double_value", "result %d");
436
    CYG_REPORT_FUNCARG1XV(this);
437
 
438
    if (!(valid_flags & (double_valid | double_invalid))) {
439
        if (valid_flags & int_valid) {
440
            Cdl::integer_to_double(int_value, double_value);
441
            valid_flags |= double_valid;
442
        } else if (valid_flags & string_valid) {
443
            if (Cdl::string_to_double(value, double_value)) {
444
                valid_flags |= double_valid;
445
            } else {
446
                valid_flags |= double_invalid;
447
            }
448
        } else {
449
            CYG_FAIL("Attempt to use uninitialized SimpleValue");
450
        }
451
    }
452
    bool result = (valid_flags & double_valid);
453
    CYG_REPORT_RETVAL(result);
454
    return result;
455
}
456
 
457
double
458
CdlSimpleValue::get_double_value() const
459
{
460
    CYG_REPORT_FUNCNAME("CdlSimpleValue::get_double_value");
461
    CYG_REPORT_FUNCARG1XV(this);
462
 
463
    double result = 0.0;
464
    if ((valid_flags & double_valid) || has_double_value()) {
465
        result = double_value;
466
    }
467
 
468
    CYG_REPORT_RETURN();
469
    return result;
470
}
471
 
472
bool
473
CdlSimpleValue::get_bool_value() const
474
{
475
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_bool_value", "result %d");
476
    CYG_REPORT_FUNCARG1XV(this);
477
 
478
    bool result = false;
479
    if (valid_flags & int_valid) {
480
        if (0 != int_value) {
481
            result = true;
482
        }
483
    } else if (valid_flags & double_valid) {
484
        // Leave it to the compiler to decide what is valid
485
        result = double_value;
486
    } else if (valid_flags & string_valid) {
487
        // string_to_bool copes with "1", "true", and a few other cases.
488
        // If the current value does not match any of these then
489
        // true corresponds to a non-empty string.
490
        if (!Cdl::string_to_bool(value, result)) {
491
            if ("" == value) {
492
                result = false;
493
            } else {
494
                result = true;
495
            }
496
        }
497
    } else {
498
        // No value defined, default to false.
499
        result = false;
500
    }
501
 
502
    CYG_REPORT_RETVAL(result);
503
    return result;
504
}
505
 
506
//}}}
507
//{{{  Updating the value               
508
 
509
// ----------------------------------------------------------------------------
510
// Normally the assignment operators will be used for this instead.
511
 
512
void
513
CdlSimpleValue::set_value(std::string val, CdlValueFormat new_format)
514
{
515
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value (string)");
516
    CYG_REPORT_FUNCARG1XV(this);
517
 
518
    value               = val;
519
    int_value           = 0;
520
    double_value        = 0.0;
521
    valid_flags         = string_valid;
522
    format              = new_format;
523
}
524
 
525
 
526
void
527
CdlSimpleValue::set_integer_value(cdl_int val, CdlValueFormat new_format)
528
{
529
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_integer_value");
530
    CYG_REPORT_FUNCARG2XV(this, (int) val);
531
 
532
    value               = "";
533
    int_value           = val;
534
    double_value        = 0.0;
535
    valid_flags         = int_valid;
536
    format              = new_format;
537
 
538
    CYG_REPORT_RETURN();
539
}
540
 
541
 
542
void
543
CdlSimpleValue::set_double_value(double val, CdlValueFormat new_format)
544
{
545
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_double_value");
546
    CYG_REPORT_FUNCARG1XV(this);
547
 
548
    value               = "";
549
    int_value           = 0;
550
    double_value        = val;
551
    valid_flags         = double_valid;
552
    format              = new_format;
553
 
554
    CYG_REPORT_RETURN();
555
}
556
 
557
//}}}
558
//{{{  Value format support             
559
 
560
// ----------------------------------------------------------------------------
561
 
562
CdlValueFormat
563
CdlSimpleValue::get_value_format() const
564
{
565
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_value_format", "result %d");
566
    CYG_REPORT_FUNCARG1XV(this);
567
 
568
    CdlValueFormat result = format;
569
    CYG_REPORT_RETVAL(result);
570
    return result;
571
}
572
 
573
void
574
CdlSimpleValue::set_value_format(CdlValueFormat new_format)
575
{
576
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
577
    CYG_REPORT_FUNCARG2XV(this, new_format);
578
 
579
    format      = new_format;
580
 
581
    CYG_REPORT_RETURN();
582
}
583
 
584
void
585
CdlSimpleValue::set_value_format(CdlSimpleValue& other_val)
586
{
587
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format (simple val)");
588
    CYG_REPORT_FUNCARG2XV(this, &other_val);
589
 
590
    format = other_val.format;
591
 
592
    CYG_REPORT_RETURN();
593
}
594
 
595
// This gets used for binary operators, e.g. A + B
596
// If A has a non-default format then that gets used.
597
// Otherwise B's format gets used, which may or may not be default.
598
//
599
// e.g. 0x1000 + 4 -> 0x1004
600
//      10 + 0x100 -> 0x10A
601
//      10 + 32    -> 42
602
 
603
void
604
CdlSimpleValue::set_value_format(CdlSimpleValue& val1, CdlSimpleValue& val2)
605
{
606
    CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
607
    CYG_REPORT_FUNCARG3XV(this, &val1, &val2);
608
 
609
    format = (CdlValueFormat_Default != val1.format) ? val1.format : val2.format;
610
 
611
    CYG_REPORT_RETURN();
612
}
613
 
614
//}}}
615
//{{{  Comparison operators             
616
 
617
// ----------------------------------------------------------------------------
618
 
619
bool
620
CdlSimpleValue::operator==(const CdlSimpleValue& other) const
621
{
622
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator==", "result %d");
623
    CYG_REPORT_FUNCARG2XV(this, &other);
624
 
625
    bool result = false;
626
 
627
    if (has_integer_value()) {
628
        if (other.has_integer_value()) {
629
            cdl_int val1 = get_integer_value();
630
            cdl_int val2 = other.get_integer_value();
631
            result = (val1 == val2);
632
        }
633
    } else if (has_double_value()) {
634
        if (other.has_double_value()) {
635
            double val1 = get_double_value();
636
            double val2 = other.get_double_value();
637
            result = (val1 == val2);
638
        }
639
    } else {
640
        std::string val1 = get_value();
641
        std::string val2 = other.get_value();
642
        result = (val1 == val2);
643
    }
644
 
645
    CYG_REPORT_RETVAL(result);
646
    return result;
647
}
648
 
649
bool
650
CdlSimpleValue::operator!=(const CdlSimpleValue& other) const
651
{
652
    CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator!=", "result %d");
653
    CYG_REPORT_FUNCARG2XV(this, &other);
654
 
655
    bool result = true;
656
    if (has_integer_value()) {
657
        if (other.has_integer_value()) {
658
            cdl_int val1 = get_integer_value();
659
            cdl_int val2 = other.get_integer_value();
660
            result = (val1 != val2);
661
        }
662
    } else if (has_double_value()) {
663
        if (other.has_double_value()) {
664
            double val1 = get_double_value();
665
            double val2 = other.get_double_value();
666
            result = (val1 != val2);
667
        }
668
    } else {
669
        std::string val1 = get_value();
670
        std::string val2 = other.get_value();
671
        result = (val1 != val2);
672
    }
673
 
674
 
675
    CYG_REPORT_RETVAL(result);
676
    return result;
677
}
678
 
679
//}}}
680
 
681
//}}}
682
//{{{  CdlValue class                   
683
 
684
// ----------------------------------------------------------------------------
685
// This should really be a class static constant, but VC++ does not implement
686
// that part of the language. A constant here avoids the need for lots of
687
// occurrences of 4 throughout the value-related routines.
688
 
689
static const int CdlValue_number_of_sources = 4;
690
 
691
//{{{  Constructors                             
692
 
693
// ----------------------------------------------------------------------------
694
// The default flavor depends on the type of entity being created. For
695
// example CDL options are boolean by default, but packages are booldata.
696
// The intelligence to do the right thing lives in set_flavor().
697
 
698
CdlValue::CdlValue(CdlValueFlavor flavor_arg)
699
{
700
    CYG_REPORT_FUNCNAME("CdlValue:: constructor");
701
    CYG_REPORT_FUNCARG1XV(this);
702
 
703
    current_source = CdlValueSource_Default;
704
    source_valid[CdlValueSource_Default]        = true;
705
    source_valid[CdlValueSource_Inferred]       = false;
706
    source_valid[CdlValueSource_Wizard]         = false;
707
    source_valid[CdlValueSource_User]           = false;
708
    enabled[CdlValueSource_Default]             = false;
709
    enabled[CdlValueSource_Inferred]            = false;
710
    enabled[CdlValueSource_Wizard]              = false;
711
    enabled[CdlValueSource_User]                = false;
712
 
713
    // The SimpleValues will initialize themselves.
714
 
715
    cdlvalue_cookie         = CdlValue_Magic;
716
    CYGDBG_MEMLEAK_CONSTRUCTOR();
717
 
718
    // This cannot happen until after the object is valid.
719
    set_flavor(flavor_arg);
720
 
721
    CYG_POSTCONDITION_THISC();
722
    CYG_REPORT_RETURN();
723
}
724
 
725
// ----------------------------------------------------------------------------
726
// Copy constructor. This is not really required, a default
727
// member-wise copy would be fine and more efficient, but it would
728
// lose tracing and assertion.
729
 
730
CdlValue::CdlValue(const CdlValue& original)
731
{
732
    CYG_REPORT_FUNCNAME("CdlValue:: copy constructor");
733
    CYG_REPORT_FUNCARG2XV(this, &original);
734
    CYG_INVARIANT_CLASSOC(CdlValue, original);
735
 
736
    flavor              = original.flavor;
737
    current_source      = original.current_source;
738
    for (int i = 0; i < CdlValue_number_of_sources; i++) {
739
        source_valid[i] = original.source_valid[i];
740
        enabled[i]      = original.enabled[i];
741
        values[i]       = original.values[i];
742
    }
743
 
744
    cdlvalue_cookie = CdlValue_Magic;
745
    CYGDBG_MEMLEAK_CONSTRUCTOR();
746
 
747
    CYG_POSTCONDITION_THISC();
748
    CYG_REPORT_RETURN();
749
}
750
 
751
// ----------------------------------------------------------------------------
752
// Assignment operator. Again this is not required, the default would be
753
// fine and more efficient, but tracing and assertions are good things.
754
 
755
CdlValue& CdlValue::operator=(const CdlValue& original)
756
{
757
    CYG_REPORT_FUNCNAME("CdlValue:: assignment operator");
758
    CYG_REPORT_FUNCARG2XV(this, &original);
759
    CYG_INVARIANT_CLASSOC(CdlValue, original);
760
 
761
    if (this != &original) {
762
        flavor          = original.flavor;
763
        current_source  = original.current_source;
764
        for (int i = 0; i < CdlValue_number_of_sources; i++) {
765
            source_valid[i]     = original.source_valid[i];
766
            enabled[i]          = original.enabled[i];
767
            values[i]           = original.values[i];
768
        }
769
    }
770
 
771
    cdlvalue_cookie = CdlValue_Magic;
772
    CYG_POSTCONDITION_THISC();
773
    CYG_REPORT_RETURN();
774
    return *this;
775
}
776
 
777
//}}}
778
//{{{  Destructor                               
779
 
780
// ----------------------------------------------------------------------------
781
 
782
CdlValue::~CdlValue()
783
{
784
    CYG_REPORT_FUNCNAME("CdlValue:: destructor");
785
    CYG_REPORT_FUNCARG1XV(this);
786
    CYG_PRECONDITION_THISC();
787
 
788
    cdlvalue_cookie     = CdlValue_Invalid;
789
    flavor              = CdlValueFlavor_Invalid;
790
    current_source      = CdlValueSource_Invalid;
791
    for (int i = 0; i < CdlValue_number_of_sources; i++) {
792
        source_valid[i]         = false;
793
        enabled[i]              = false;
794
        // The CdlSimpleValue array will take care of itself.
795
    }
796
    CYGDBG_MEMLEAK_DESTRUCTOR();
797
 
798
    CYG_REPORT_RETURN();
799
}
800
 
801
//}}}
802
//{{{  check_this()                             
803
 
804
// ----------------------------------------------------------------------------
805
bool
806
CdlValue::check_this(cyg_assert_class_zeal zeal) const
807
{
808
    if (CdlValue_Magic != cdlvalue_cookie) {
809
        return false;
810
    }
811
    CYGDBG_MEMLEAK_CHECKTHIS();
812
 
813
    if (!source_valid[CdlValueSource_Default]) {
814
        return false;
815
    }
816
 
817
    if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Data == flavor)) {
818
        for (int i = 0; i < CdlValue_number_of_sources; i++) {
819
            if (!enabled[i]) {
820
                return false;
821
            }
822
        }
823
    }
824
    for (int i = 0; i < CdlValue_number_of_sources; i++) {
825
        if (source_valid[i]) {
826
            if (!values[i].check_this(zeal)) {
827
                return false;
828
            }
829
        }
830
    }
831
 
832
    return true;
833
}
834
 
835
//}}}
836
//{{{  Flavor manipulation                      
837
 
838
// ----------------------------------------------------------------------------
839
// Get hold of the current flavor.
840
CdlValueFlavor
841
CdlValue::get_flavor(void) const
842
{
843
    CYG_REPORT_FUNCNAMETYPE("CdlValue::get_flavor", "result %d");
844
    CYG_REPORT_FUNCARG1XV(this);
845
    CYG_PRECONDITION_THISC();
846
 
847
    CdlValueFlavor result = flavor;
848
    CYG_REPORT_RETVAL(result);
849
    return result;
850
}
851
 
852
// ----------------------------------------------------------------------------
853
// set_flavor() may be invoked once or twice for a given entity. The first
854
// time is from inside the constructor with the default flavor for this
855
// particular class of entity. It may then be called again if the
856
// entity has a "flavor" property that overrides this. All old data
857
// will be lost, so evaluating a default value etc. should be done after
858
// the call to set_flavor(), and there should be no subsequent calls to
859
// set_flavor().
860
 
861
void
862
CdlValue::set_flavor(CdlValueFlavor flavor_arg)
863
{
864
    CYG_REPORT_FUNCNAME("CdlValue:: set_flavor");
865
    CYG_REPORT_FUNCARG2XV(this, flavor_arg);
866
 
867
    // No precondition here, set_flavor() is called from inside the constructor
868
    CYG_PRECONDITIONC((CdlValueFlavor_None     == flavor_arg) || \
869
                      (CdlValueFlavor_Bool     == flavor_arg) || \
870
                      (CdlValueFlavor_BoolData == flavor_arg) || \
871
                      (CdlValueFlavor_Data     == flavor_arg));
872
 
873
    flavor = flavor_arg;
874
    switch(flavor) {
875
      case CdlValueFlavor_None :
876
        {
877
            // All value sources are enabled, but "default" remains
878
            // the only valid one. All data parts are set to "1",
879
            // although that should not really matter.
880
            enabled[CdlValueSource_Default]     = true;
881
            enabled[CdlValueSource_Inferred]    = true;
882
            enabled[CdlValueSource_Wizard]      = true;
883
            enabled[CdlValueSource_User]        = true;
884
 
885
            CdlSimpleValue simple_val((cdl_int) 1);
886
            values[CdlValueSource_Default]      = simple_val;
887
            values[CdlValueSource_Inferred]     = simple_val;
888
            values[CdlValueSource_Wizard]       = simple_val;
889
            values[CdlValueSource_User]         = simple_val;
890
            break;
891
        }
892
 
893
      case CdlValueFlavor_Bool :
894
        {
895
            // All value sources start out as disabled, but with a
896
            // constant data part of 1. Users can only control the
897
            // boolean part. This is consistent with header file
898
            // generation: no #define is generated for disabled
899
            // options, but if the option is enabled then the data
900
            // part will be used for the value.
901
            enabled[CdlValueSource_Default]     = false;
902
            enabled[CdlValueSource_Inferred]    = false;
903
            enabled[CdlValueSource_Wizard]      = false;
904
            enabled[CdlValueSource_User]        = false;
905
 
906
            // BLV - keep the data part at 0 for now. There is too
907
            // much confusion in the code between value as a string
908
            // representation, and value as the data part of the
909
            // bool/data pair. This needs to be fixed, but it requires
910
            // significant API changes.
911
#if 0            
912
            CdlSimpleValue simple_val(cdl_int(1));
913
#else
914
            CdlSimpleValue simple_val(cdl_int(0));
915
#endif            
916
            values[CdlValueSource_Default]      = simple_val;
917
            values[CdlValueSource_Inferred]     = simple_val;
918
            values[CdlValueSource_Wizard]       = simple_val;
919
            values[CdlValueSource_User]         = simple_val;
920
            break;
921
        }
922
 
923
      case CdlValueFlavor_BoolData :
924
        {
925
            // All value sources start out as disabled, just like
926
            // booleans. Nothing is known about the data part.
927
            enabled[CdlValueSource_Default]       = false;
928
            enabled[CdlValueSource_Inferred]      = false;
929
            enabled[CdlValueSource_Wizard]        = false;
930
            enabled[CdlValueSource_User]          = false;
931
            break;
932
        }
933
 
934
      case CdlValueFlavor_Data :
935
        {
936
            // All value sources start out as enabled, and cannot be
937
            // changed. Nothing is known about the data part.
938
            enabled[CdlValueSource_Default]       = true;
939
            enabled[CdlValueSource_Inferred]      = true;
940
            enabled[CdlValueSource_Wizard]        = true;
941
            enabled[CdlValueSource_User]          = true;
942
            break;
943
        }
944
 
945
      default :
946
        break;
947
    }
948
 
949
    CYG_REPORT_RETURN();
950
}
951
 
952
//}}}
953
//{{{  Source manipulation                      
954
 
955
// ----------------------------------------------------------------------------
956
 
957
void
958
CdlValue::set_source(CdlValueSource source)
959
{
960
    CYG_REPORT_FUNCNAME("CdlValue::set_source");
961
    CYG_REPORT_FUNCARG2XV(this, source);
962
    CYG_INVARIANT_THISC(CdlValue);
963
    CYG_PRECONDITIONC((0 <= source) && (source <= CdlValue_number_of_sources));
964
    CYG_PRECONDITIONC(source_valid[source]);
965
 
966
    current_source = source;
967
 
968
    CYG_REPORT_RETURN();
969
}
970
 
971
CdlValueSource
972
CdlValue::get_source(void) const
973
{
974
    CYG_REPORT_FUNCNAMETYPE("CdlValue::get_source", "source %d");
975
    CYG_REPORT_FUNCARG1XV(this);
976
    CYG_PRECONDITION_THISC();
977
 
978
    CdlValueSource result = current_source;
979
    CYG_REPORT_RETVAL(result);
980
    return result;
981
}
982
 
983
bool
984
CdlValue::has_source(CdlValueSource source) const
985
{
986
    CYG_REPORT_FUNCNAMETYPE("CdlValue::has_source", "result %d");
987
    CYG_REPORT_FUNCARG2XV(this, source);
988
    CYG_PRECONDITION_THISC();
989
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
990
 
991
    bool result = source_valid[source];
992
    CYG_REPORT_RETVAL(result);
993
    return result;
994
}
995
 
996
// ----------------------------------------------------------------------------
997
// Invalidate a specific source. If that source happens to be the current one,
998
// switch to the highest-priority valid source.
999
 
1000
void
1001
CdlValue::invalidate_source(CdlValueSource source)
1002
{
1003
    CYG_REPORT_FUNCNAME("CdlValue::invalidate_source");
1004
    CYG_REPORT_FUNCARG2XV(this, source);
1005
    CYG_PRECONDITION_THISC();
1006
    CYG_PRECONDITIONC(CdlValueSource_Default != source);
1007
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1008
 
1009
    if (CdlValueSource_Default != source) {
1010
        source_valid[source]        = false;
1011
        if (current_source == source) {
1012
            if (source_valid[CdlValueSource_User]) {
1013
                current_source = CdlValueSource_User;
1014
            } else if (source_valid[CdlValueSource_Wizard]) {
1015
                current_source = CdlValueSource_Wizard;
1016
            } else if (source_valid[CdlValueSource_Inferred]) {
1017
                current_source = CdlValueSource_Inferred;
1018
            } else {
1019
                current_source = CdlValueSource_Default;
1020
            }
1021
        }
1022
    }
1023
 
1024
    CYG_POSTCONDITIONC(source_valid[current_source]);
1025
}
1026
 
1027
//}}}
1028
//{{{  Retrieving the data                      
1029
 
1030
// ----------------------------------------------------------------------------
1031
// Check the enabled flag for the appropriate source. The specified source
1032
// is normally provided by a default argument CdlValueSource_Current, which
1033
// 99.9...% of the time is what we are after.
1034
//
1035
// Note that this member can be used even for entities of flavor none
1036
// and data, and the result will be true. However it is not legal to
1037
// disable such entities.
1038
 
1039
bool
1040
CdlValue::is_enabled(CdlValueSource source) const
1041
{
1042
    CYG_REPORT_FUNCNAMETYPE("CdlValue::is_enabled", "enabled %d");
1043
    CYG_REPORT_FUNCARG2XV(this, source);
1044
    CYG_PRECONDITION_THISC();
1045
 
1046
    if (CdlValueSource_Current == source) {
1047
        source = current_source;
1048
    }
1049
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1050
    CYG_PRECONDITIONC(source_valid[source]);
1051
 
1052
    bool result = enabled[source];
1053
    CYG_REPORT_RETVAL(result);
1054
    return result;
1055
}
1056
 
1057
// ----------------------------------------------------------------------------
1058
// Access to the value field.
1059
 
1060
std::string
1061
CdlValue::get_value(CdlValueSource source) const
1062
{
1063
    CYG_REPORT_FUNCNAME("CdlValue::get_value");
1064
    CYG_REPORT_FUNCARG2XV(this, source);
1065
    CYG_PRECONDITION_THISC();
1066
 
1067
    if (CdlValueSource_Current == source) {
1068
        source = current_source;
1069
    }
1070
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1071
    CYG_PRECONDITIONC(source_valid[source]);
1072
 
1073
    std::string result = values[source].get_value();
1074
    CYG_REPORT_RETURN();
1075
    return result;
1076
}
1077
 
1078
bool
1079
CdlValue::has_integer_value(CdlValueSource source) const
1080
{
1081
    CYG_REPORT_FUNCNAMETYPE("CdlValue::has_integer_value", "result %d");
1082
    CYG_REPORT_FUNCARG2XV(this, source);
1083
    CYG_INVARIANT_THISC(CdlValue);
1084
 
1085
    if (CdlValueSource_Current == source) {
1086
        source = current_source;
1087
    }
1088
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1089
    CYG_PRECONDITIONC(source_valid[source]);
1090
 
1091
    bool result = values[source].has_integer_value();
1092
    CYG_REPORT_RETVAL(result);
1093
    return result;
1094
}
1095
 
1096
bool
1097
CdlValue::has_double_value(CdlValueSource source) const
1098
{
1099
    CYG_REPORT_FUNCNAMETYPE("CdlValue::has_value", "result %d");
1100
    CYG_REPORT_FUNCARG2XV(this, source);
1101
    CYG_INVARIANT_THISC(CdlValue);
1102
 
1103
    if (CdlValueSource_Current == source) {
1104
        source = current_source;
1105
    }
1106
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1107
    CYG_PRECONDITIONC(source_valid[source]);
1108
 
1109
    bool result = values[source].has_double_value();
1110
    CYG_REPORT_RETVAL(result);
1111
    return result;
1112
}
1113
 
1114
cdl_int
1115
CdlValue::get_integer_value(CdlValueSource source) const
1116
{
1117
    CYG_REPORT_FUNCNAMETYPE("CdlValue::get_integer_value", "value %ld");
1118
    CYG_REPORT_FUNCARG2XV(this, source);
1119
    CYG_PRECONDITION_THISC();
1120
 
1121
    if (CdlValueSource_Current == source) {
1122
        source = current_source;
1123
    }
1124
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1125
    CYG_PRECONDITIONC(source_valid[source]);
1126
 
1127
    cdl_int result = values[source].get_integer_value();
1128
    CYG_REPORT_RETVAL(result);
1129
    return result;
1130
}
1131
 
1132
double
1133
CdlValue::get_double_value(CdlValueSource source) const
1134
{
1135
    CYG_REPORT_FUNCNAME("CdlValue::get_double_value");
1136
    CYG_REPORT_FUNCARG2XV(this, source);
1137
    CYG_PRECONDITION_THISC();
1138
 
1139
    if (CdlValueSource_Current == source) {
1140
        source = current_source;
1141
    }
1142
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1143
    CYG_PRECONDITIONC(source_valid[source]);
1144
 
1145
    double result = values[source].get_double_value();
1146
    CYG_REPORT_RETURN();
1147
    return result;
1148
}
1149
 
1150
CdlSimpleValue
1151
CdlValue::get_simple_value(CdlValueSource source) const
1152
{
1153
    CYG_REPORT_FUNCNAME("CdlValue::get_simple_value");
1154
    CYG_REPORT_FUNCARG2XV(this, source);
1155
    CYG_PRECONDITION_THISC();
1156
 
1157
    if (CdlValueSource_Current == source) {
1158
        source = current_source;
1159
    }
1160
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1161
    CYG_PRECONDITIONC(source_valid[source]);
1162
 
1163
    CYG_REPORT_RETURN();
1164
    return values[source];
1165
}
1166
 
1167
//}}}
1168
//{{{  Value modification                       
1169
 
1170
// ----------------------------------------------------------------------------
1171
 
1172
void
1173
CdlValue::set_enabled(bool val, CdlValueSource source)
1174
{
1175
    CYG_REPORT_FUNCNAME("CdlValue::set_enabled");
1176
    CYG_REPORT_FUNCARG3XV(this, val, source);
1177
    CYG_INVARIANT_THISC(CdlValue);
1178
    CYG_PRECONDITIONC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
1179
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1180
 
1181
    enabled[source] = val;
1182
    source_valid[source] = true;
1183
    if (source > current_source) {
1184
        current_source = source;
1185
    }
1186
 
1187
    CYG_REPORT_RETURN();
1188
}
1189
 
1190
void
1191
CdlValue::set_value(CdlSimpleValue& val, CdlValueSource source)
1192
{
1193
    CYG_REPORT_FUNCNAME("CdlValue::set_value");
1194
    CYG_REPORT_FUNCARG3XV(this, &val, source);
1195
    CYG_INVARIANT_THISC(CdlValue);
1196
    CYG_PRECONDITIONC((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1197
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1198
 
1199
    values[source] = val;
1200
    source_valid[source] = true;
1201
    if (source > current_source) {
1202
        current_source = source;
1203
    }
1204
 
1205
    CYG_REPORT_RETURN();
1206
}
1207
 
1208
void
1209
CdlValue::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
1210
{
1211
    CYG_REPORT_FUNCNAME("CdlValue::set_enabled_and_value");
1212
    CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
1213
    CYG_INVARIANT_THISC(CdlValue);
1214
    CYG_PRECONDITIONC(CdlValueFlavor_BoolData == flavor);
1215
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1216
 
1217
    enabled[source]      = enabled_arg;
1218
    values[source]       = val;
1219
    source_valid[source] = true;
1220
    if (source > current_source) {
1221
        current_source = source;
1222
    }
1223
 
1224
    CYG_REPORT_RETURN();
1225
}
1226
 
1227
// ----------------------------------------------------------------------------
1228
// Given a SimpleValue, this member function does the right thing
1229
// for the flavor.
1230
 
1231
void
1232
CdlValue::set(CdlSimpleValue& val, CdlValueSource source)
1233
{
1234
    CYG_REPORT_FUNCNAME("CdlValue::set");
1235
    CYG_REPORT_FUNCARG3XV(this, &val, source);
1236
    CYG_INVARIANT_THISC(CdlValue);
1237
    CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1238
    CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1239
 
1240
    switch(flavor) {
1241
      case CdlValueFlavor_Bool:
1242
        enabled[source] = val.get_bool_value();
1243
        break;
1244
 
1245
      case CdlValueFlavor_BoolData:
1246
        if (!val.get_bool_value()) {
1247
            enabled[source] = false;
1248
            values[source]  = (cdl_int) 0;
1249
        } else {
1250
            enabled[source] = true;
1251
            values[source]  = val;
1252
        }
1253
        break;
1254
 
1255
      case CdlValueFlavor_Data:
1256
        values[source] = val;
1257
        break;
1258
 
1259
      default:
1260
        CYG_FAIL("Unknown value flavor detected.");
1261
    }
1262
 
1263
    source_valid[source] = true;
1264
    if (source > current_source) {
1265
        current_source = source;
1266
    }
1267
 
1268
    CYG_REPORT_RETURN();
1269
}
1270
 
1271
//}}}
1272
 
1273
//}}}
1274
//{{{  CdlListValue class               
1275
 
1276
// ----------------------------------------------------------------------------
1277
// List values. Most of this is straightforward.
1278
 
1279
CdlListValue::CdlListValue()
1280
{
1281
    CYG_REPORT_FUNCNAME("CdlListValue:: default constructor");
1282
    CYG_REPORT_FUNCARG1XV(this);
1283
 
1284
    // The only data fields are embedded objects which will have been
1285
    // filled in already.
1286
    cdllistvalue_cookie = CdlListValue_Magic;
1287
    CYGDBG_MEMLEAK_CONSTRUCTOR();
1288
 
1289
    CYG_POSTCONDITION_THISC();
1290
    CYG_REPORT_RETURN();
1291
}
1292
 
1293
CdlListValue::CdlListValue(const CdlListValue& original)
1294
{
1295
    CYG_REPORT_FUNCNAME("CdlListValue:: copy constructor");
1296
    CYG_REPORT_FUNCARG2XV(this, &original);
1297
    CYG_INVARIANT_CLASSOC(CdlListValue, original);
1298
 
1299
    // This may get expensive, but should not happen very often.
1300
    table               = original.table;
1301
    integer_ranges      = original.integer_ranges;
1302
    double_ranges       = original.double_ranges;
1303
    cdllistvalue_cookie = CdlListValue_Magic;
1304
    CYGDBG_MEMLEAK_CONSTRUCTOR();
1305
 
1306
    CYG_POSTCONDITION_THISC();
1307
    CYG_REPORT_RETURN();
1308
}
1309
 
1310
CdlListValue & CdlListValue::operator=(const CdlListValue& original)
1311
{
1312
    CYG_REPORT_FUNCNAME("CdlListValue:: assignment operator");
1313
    CYG_REPORT_FUNCARG2XV(this, &original);
1314
    CYG_INVARIANT_CLASSOC(CdlListValue, original);
1315
 
1316
    if (this != &original) {
1317
        table.clear();
1318
        integer_ranges.clear();
1319
        double_ranges.clear();
1320
        table          = original.table;
1321
        integer_ranges = original.integer_ranges;
1322
        double_ranges  = original.double_ranges;
1323
    }
1324
 
1325
    CYG_POSTCONDITION_THISC();
1326
    CYG_REPORT_RETURN();
1327
    return *this;
1328
}
1329
 
1330
CdlListValue::~CdlListValue()
1331
{
1332
    CYG_REPORT_FUNCNAME("CdlListValue:: destructor");
1333
    CYG_REPORT_FUNCARG1XV(this);
1334
    CYG_PRECONDITION_THISC();
1335
 
1336
    cdllistvalue_cookie = CdlListValue_Invalid;
1337
    table.clear();
1338
    integer_ranges.clear();
1339
    double_ranges.clear();
1340
    CYGDBG_MEMLEAK_DESTRUCTOR();
1341
 
1342
    CYG_REPORT_RETURN();
1343
}
1344
 
1345
// ----------------------------------------------------------------------------
1346
// Finding out about the current legal values. These routines can be
1347
// used by GUI-related code to figure out a sensible widget to be used
1348
// for a CDL entity. In nearly all cases life will be simple: either
1349
// there will be a fixed set of legal values and the user merely has
1350
// to choose one of these; or there will be a simple numerical range.
1351
// Occasionally life may be more complicated, if the full generality
1352
// of CDL list expressions is being used, and it will be necessary to
1353
// use an entry box instead. Note that the entity's flavor may also
1354
// affect the user interface.
1355
 
1356
const std::vector<CdlSimpleValue>&
1357
CdlListValue::get_table(void) const
1358
{
1359
    CYG_REPORT_FUNCNAME("CdlListValue::get_table");
1360
    CYG_REPORT_FUNCARG1XV(this);
1361
    CYG_PRECONDITION_THISC();
1362
 
1363
    CYG_REPORT_RETURN();
1364
    return table;
1365
}
1366
 
1367
const std::vector<std::pair<cdl_int, cdl_int> >&
1368
CdlListValue::get_integer_ranges(void) const
1369
{
1370
    CYG_REPORT_FUNCNAME("CdlListValue::get_integer_ranges");
1371
    CYG_REPORT_FUNCARG1XV(this);
1372
    CYG_PRECONDITION_THISC();
1373
 
1374
    CYG_REPORT_RETURN();
1375
    return integer_ranges;
1376
}
1377
 
1378
const std::vector<std::pair<double, double> >&
1379
CdlListValue::get_double_ranges(void) const
1380
{
1381
    CYG_REPORT_FUNCNAME("CdlListValue::get_double_ranges");
1382
    CYG_REPORT_FUNCARG1XV(this);
1383
    CYG_PRECONDITION_THISC();
1384
 
1385
    CYG_REPORT_RETURN();
1386
    return double_ranges;
1387
}
1388
 
1389
// ----------------------------------------------------------------------------
1390
// Membership. This can be quite complicated.
1391
//
1392
// 1) anything which has an integer representation must be checked against
1393
//    the integer ranges and the vector of integer constants. It must
1394
//    also be checked against the floating point ranges, since calculations
1395
//    may have resulted in the fractional part disappearing, assuming that
1396
//    the integer has a floating point representation.
1397
//
1398
// 2) similarly anything which has a floating point representation must
1399
//    be checked against the floating point ranges and constant vector.
1400
//    In addition it may have an empty fractional part in which case
1401
//    integer comparisons have to be attempted as well.
1402
//
1403
// 3) string data needs to be tested first of all for integer and double
1404
//    representations. If these fail then the comparison should be against
1405
//    the string vector.
1406
//
1407
// For floating point data exact comparisons are of course meaningless,
1408
// and arguably the vector of floating point constants is useless. The
1409
// ranges vector is better, but still not ideal. It may be necessary
1410
// to introduce an epsilon fudge factor.
1411
 
1412
bool
1413
CdlListValue::is_member(CdlSimpleValue& val) const
1414
{
1415
    CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (CdlSimpleValue)", "result %d");
1416
    CYG_REPORT_FUNCARG2XV(this, &val);
1417
    CYG_PRECONDITION_THISC();
1418
 
1419
    bool result = false;
1420
    if (val.has_integer_value()) {
1421
        result = is_member(val.get_integer_value(), false);
1422
    }
1423
    if (!result && val.has_double_value()) {
1424
        result = is_member(val.get_double_value(), false);
1425
    }
1426
    if (!result) {
1427
        result = is_member(val.get_value());
1428
    }
1429
 
1430
    CYG_REPORT_RETVAL(result);
1431
    return result;
1432
}
1433
 
1434
bool
1435
CdlListValue::is_member(std::string val, bool allow_conversions) const
1436
{
1437
    CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (string)", "result %d");
1438
    CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1439
    CYG_PRECONDITION_THISC();
1440
 
1441
    bool        result = false;
1442
    if (allow_conversions) {
1443
        cdl_int     integer_value;
1444
        double      double_value;
1445
 
1446
        if (Cdl::string_to_integer(val, integer_value)) {
1447
            result = is_member(integer_value, false);
1448
        }
1449
        if (!result && Cdl::string_to_double(val, double_value)) {
1450
            result = is_member(double_value, false);
1451
        }
1452
    }
1453
    if (!result) {
1454
        for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1455
            if (val_i->get_value() == val) {
1456
                result = true;
1457
                break;
1458
            }
1459
        }
1460
    }
1461
 
1462
    CYG_REPORT_RETVAL(result);
1463
    return result;
1464
}
1465
 
1466
bool
1467
CdlListValue::is_member(cdl_int val, bool allow_conversions) const
1468
{
1469
    CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (int)", "result %d");
1470
    CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1471
    CYG_PRECONDITION_THISC();
1472
 
1473
    bool result = false;
1474
    for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1475
        if (val_i->has_integer_value() && (val_i->get_integer_value() == val)) {
1476
            result = true;
1477
            break;
1478
        }
1479
    }
1480
    if (!result) {
1481
        for (std::vector<std::pair<cdl_int,cdl_int> >::const_iterator i = integer_ranges.begin();
1482
             i != integer_ranges.end(); i++) {
1483
            if ((val >= i->first) && (val <= i->second)) {
1484
                result = true;
1485
                break;
1486
            }
1487
        }
1488
    }
1489
    if (!result && allow_conversions) {
1490
        double double_value = Cdl::integer_to_double(val);
1491
        result = is_member(double_value, false);
1492
    }
1493
 
1494
    CYG_REPORT_RETVAL(result);
1495
    return result;
1496
}
1497
 
1498
bool
1499
CdlListValue::is_member(double val, bool allow_conversions) const
1500
{
1501
    CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (double)", "result %d");
1502
    CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1503
    CYG_PRECONDITION_THISC();
1504
 
1505
    bool result = false;
1506
    for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1507
        if (val_i->has_double_value() && (val_i->get_double_value() == val)) {
1508
            result = true;
1509
            break;
1510
        }
1511
    }
1512
    if (!result) {
1513
        for (std::vector<std::pair<double,double> >::const_iterator i = double_ranges.begin();
1514
             i != double_ranges.end(); i++) {
1515
            if ((val >= i->first) && (val <= i->second)) {
1516
                result = true;
1517
                break;
1518
            }
1519
        }
1520
    }
1521
    if (!result && allow_conversions) {
1522
        cdl_int integer_value;
1523
        if (Cdl::double_to_integer(val, integer_value)) {
1524
            result = is_member(integer_value, false);
1525
        }
1526
    }
1527
 
1528
    CYG_REPORT_RETVAL(result);
1529
    return result;
1530
}
1531
 
1532
// ----------------------------------------------------------------------------
1533
 
1534
bool
1535
CdlListValue::check_this(cyg_assert_class_zeal zeal) const
1536
{
1537
    if (CdlListValue_Magic != cdllistvalue_cookie) {
1538
        return false;
1539
    }
1540
    CYGDBG_MEMLEAK_CHECKTHIS();
1541
 
1542
    // After construction the various vectors will still be empty, they
1543
    // do not get filled in until a list expression is evaluated. No
1544
    // further tests are possible here.
1545
    return true;
1546
}
1547
 
1548
//}}}
1549
 
1550
//{{{  dialog property                  
1551
 
1552
// ----------------------------------------------------------------------------
1553
// Syntax: dialog <reference>
1554
 
1555
void
1556
CdlValuableBody::dialog_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1557
                                       CdlUpdate change)
1558
{
1559
    CYG_REPORT_FUNCNAME("CdlValuable::dialog_update_handler");
1560
    CYG_PRECONDITION_CLASSC(transaction);
1561
    CYG_PRECONDITION_CLASSC(source);
1562
    CYG_PRECONDITION_CLASSC(prop);
1563
 
1564
    // The main update of interest is Loaded (iff dest != 0), and
1565
    // Created. These updates indicate that the destination now exists,
1566
    // so it is possible to check that the destination is a dialog.
1567
    if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1568
        (CdlUpdate_Created == change)) {
1569
 
1570
        CYG_ASSERT_CLASSC(dest);
1571
        CdlDialog dialog = dynamic_cast<CdlDialog>(dest);
1572
        if (0 == dialog) {
1573
            std::string msg = dest->get_class_name() + " " + dest->get_name() +
1574
                " cannot be used in a dialog property, it is not a custom dialog.";
1575
            CdlConflict_DataBody::make(transaction, source, prop, msg);
1576
        }
1577
 
1578
    } else if (CdlUpdate_Destroyed == change) {
1579
        // If there was a data conflict object, it is no longer relevant
1580
        transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1581
    }
1582
 
1583
    CYG_REPORT_RETURN();
1584
}
1585
 
1586
int
1587
CdlValuableBody::parse_dialog(CdlInterpreter interp, int argc, const char* argv[])
1588
{
1589
    CYG_REPORT_FUNCNAMETYPE("parse_dialog", "result %d");
1590
 
1591
    int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Dialog, 0, 0, false, &dialog_update_handler);
1592
 
1593
    CYG_REPORT_RETVAL(result);
1594
    return result;
1595
}
1596
 
1597
bool
1598
CdlValuableBody::has_dialog() const
1599
{
1600
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_dialog", "result %d");
1601
    CYG_REPORT_FUNCARG1XV(this);
1602
    CYG_PRECONDITION_THISC();
1603
 
1604
    // It is not enough to have the property, the dialog reference must also be
1605
    // resolved and go to a dialog.
1606
    bool        result          = false;
1607
    CdlProperty property        = get_property(CdlPropertyId_Dialog);
1608
    if (0 != property) {
1609
        CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1610
        CYG_ASSERTC(0 != ref_prop);
1611
 
1612
        CdlNode destination = ref_prop->get_destination();
1613
        if (0 != destination) {
1614
            CdlDialog dialog = dynamic_cast<CdlDialog>(destination);
1615
            if (0 != dialog) {
1616
                result = true;
1617
            }
1618
        }
1619
    }
1620
    CYG_REPORT_RETVAL(result);
1621
    return result;
1622
}
1623
 
1624
 
1625
CdlDialog
1626
CdlValuableBody::get_dialog() const
1627
{
1628
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_dialog", "result %p");
1629
    CYG_REPORT_FUNCARG1XV(this);
1630
    CYG_PRECONDITION_THISC();
1631
 
1632
    CdlDialog   result          = 0;
1633
    CdlProperty property        = get_property(CdlPropertyId_Dialog);
1634
    if (0 != property) {
1635
        CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1636
        CYG_ASSERTC(0 != ref_prop);
1637
 
1638
        CdlNode destination = ref_prop->get_destination();
1639
        if (0 != destination) {
1640
            result = dynamic_cast<CdlDialog>(destination);
1641
        }
1642
    }
1643
 
1644
    CYG_REPORT_RETVAL(result);
1645
    return result;
1646
}
1647
 
1648
//}}}
1649
//{{{  wizard property                  
1650
 
1651
// ----------------------------------------------------------------------------
1652
// Syntax: wizard <reference>
1653
 
1654
void
1655
CdlValuableBody::wizard_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1656
                                       CdlUpdate change)
1657
{
1658
    CYG_REPORT_FUNCNAME("CdlValuable::wizard_update_handler");
1659
    CYG_PRECONDITION_CLASSC(transaction);
1660
    CYG_PRECONDITION_CLASSC(source);
1661
    CYG_PRECONDITION_CLASSC(prop);
1662
 
1663
    // The main update of interest is Loaded (iff dest != 0), and
1664
    // Created. These updates indicate that the destination now exists,
1665
    // so it is possible to check that the destination is a dialog.
1666
    if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1667
        (CdlUpdate_Created == change)) {
1668
 
1669
        CYG_ASSERT_CLASSC(dest);
1670
        CdlWizard wizard = dynamic_cast<CdlWizard>(dest);
1671
        if (0 == wizard) {
1672
            std::string msg = dest->get_class_name() + " " + dest->get_name() +
1673
                " cannot be used in a wizard property, it is not a wizard.";
1674
            CdlConflict_DataBody::make(transaction, source, prop, msg);
1675
        }
1676
 
1677
    } else if (CdlUpdate_Destroyed == change) {
1678
        // If there was a data conflict object, it is no longer relevant
1679
        transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1680
    }
1681
 
1682
    CYG_REPORT_RETURN();
1683
}
1684
 
1685
int
1686
CdlValuableBody::parse_wizard(CdlInterpreter interp, int argc, const char* argv[])
1687
{
1688
    CYG_REPORT_FUNCNAMETYPE("parse_wizard", "result %d");
1689
 
1690
    int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Wizard, 0, 0, false, &wizard_update_handler);
1691
    CYG_REPORT_RETVAL(result);
1692
    return result;
1693
}
1694
 
1695
bool
1696
CdlValuableBody::has_wizard() const
1697
{
1698
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_wizard", "result %d");
1699
    CYG_REPORT_FUNCARG1XV(this);
1700
    CYG_PRECONDITION_THISC();
1701
 
1702
    // It is not enough to have the property, the wizard reference
1703
    // must also be resolved to a wizard object.
1704
    bool        result          = false;
1705
    CdlProperty property        = get_property(CdlPropertyId_Wizard);
1706
    if (0 != property) {
1707
        CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1708
        CYG_ASSERTC(0 != ref_prop);
1709
 
1710
        CdlNode destination = ref_prop->get_destination();
1711
        if (0 != destination) {
1712
            CdlWizard wizard = dynamic_cast<CdlWizard>(destination);
1713
            CYG_ASSERTC(0 != wizard);
1714
            CYG_UNUSED_PARAM(CdlWizard, wizard);
1715
            result = true;
1716
        }
1717
    }
1718
    CYG_REPORT_RETVAL(result);
1719
    return result;
1720
}
1721
 
1722
CdlWizard
1723
CdlValuableBody::get_wizard() const
1724
{
1725
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_wizard", "result %p");
1726
    CYG_REPORT_FUNCARG1XV(this);
1727
    CYG_PRECONDITION_THISC();
1728
 
1729
    CdlWizard   result          = 0;
1730
    CdlProperty property        = get_property(CdlPropertyId_Wizard);
1731
    if (0 != property) {
1732
        CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1733
        CYG_ASSERTC(0 != ref_prop);
1734
 
1735
        CdlNode destination = ref_prop->get_destination();
1736
        if (0 != destination) {
1737
            result = dynamic_cast<CdlWizard>(destination);
1738
            CYG_ASSERTC(0 != result);
1739
        }
1740
    }
1741
 
1742
    CYG_REPORT_RETVAL(result);
1743
    return result;
1744
}
1745
 
1746
//}}}
1747
//{{{  legal_values property            
1748
 
1749
// ----------------------------------------------------------------------------
1750
// Syntax: legal_values <list expression>
1751
 
1752
void
1753
CdlValuableBody::legal_values_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1754
                                             CdlUpdate change)
1755
{
1756
    CYG_REPORT_FUNCNAME("legal_values_update_handler");
1757
 
1758
    // Loaded and Unloading are of no immediate interest, reference
1759
    // updating happens in the calling code.
1760
    //
1761
    // Any other change can affect the list expression and hence
1762
    // invalidate the current value.
1763
    if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1764
        CYG_REPORT_RETURN();
1765
        return;
1766
    }
1767
 
1768
    CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1769
    CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(prop);
1770
    CYG_ASSERT_CLASSC(valuable);
1771
    CYG_ASSERT_CLASSC(lexpr);
1772
 
1773
    valuable->check_value(transaction);
1774
 
1775
    CYG_UNUSED_PARAM(CdlNode, dest);
1776
    CYG_UNUSED_PARAM(CdlProperty_ListExpression, lexpr);
1777
    CYG_REPORT_RETURN();
1778
}
1779
 
1780
int
1781
CdlValuableBody::parse_legal_values(CdlInterpreter interp, int argc, const char* argv[])
1782
{
1783
    CYG_REPORT_FUNCNAMETYPE("parse_legal_values", "result %d");
1784
 
1785
    int result = CdlParse::parse_listexpression_property(interp, argc, argv, CdlPropertyId_LegalValues, 0, 0,
1786
                                                         &legal_values_update_handler);
1787
    CYG_REPORT_RETVAL(result);
1788
    return result;
1789
}
1790
 
1791
bool
1792
CdlValuableBody::has_legal_values() const
1793
{
1794
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_legal_values", "result %d");
1795
    CYG_REPORT_FUNCARG1XV(this);
1796
    CYG_PRECONDITION_THISC();
1797
 
1798
    bool result = has_property(CdlPropertyId_LegalValues);
1799
    CYG_REPORT_RETVAL(result);
1800
    return result;
1801
}
1802
 
1803
CdlProperty_ListExpression
1804
CdlValuableBody::get_legal_values() const
1805
{
1806
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_legal_values", "result %p");
1807
    CYG_REPORT_FUNCARG1XV(this);
1808
    CYG_PRECONDITION_THISC();
1809
 
1810
    CdlProperty_ListExpression result = 0;
1811
    CdlProperty       property          = get_property(CdlPropertyId_LegalValues);
1812
    if (0 != property) {
1813
        result = dynamic_cast<CdlProperty_ListExpression>(property);
1814
        CYG_ASSERTC(0 != result);
1815
    }
1816
 
1817
    CYG_REPORT_RETVAL(result);
1818
    return result;
1819
}
1820
 
1821
//}}}
1822
//{{{  default_value property           
1823
 
1824
// ----------------------------------------------------------------------------
1825
// syntax: default_value <expr>
1826
 
1827
void
1828
CdlValuableBody::default_value_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1829
                                              CdlUpdate change)
1830
{
1831
    CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1832
    CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1833
 
1834
    // Loaded and unloading should be ignored.
1835
    if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1836
        CYG_REPORT_RETURN();
1837
        return;
1838
    }
1839
 
1840
    // Init, Created, Destroyed, ValueChange and ActiveChange should
1841
    // all result in the expression being re-evaluated and the result
1842
    // applied.
1843
    CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1844
    CYG_ASSERTC(0 != valuable);
1845
    CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1846
    CYG_ASSERTC(0 != expr);
1847
 
1848
    CdlSimpleValue val;
1849
 
1850
    try {
1851
 
1852
        CdlEvalContext context(transaction, source, prop);
1853
        expr->eval(context, val);
1854
 
1855
        valuable->set(transaction, val, CdlValueSource_Default);
1856
 
1857
    } catch(CdlEvalException e) {
1858
 
1859
 
1860
        // An EvalException conflict will have been created, so the
1861
        // user knows that this default_value is not kosher. It is
1862
        // still a good idea to make sure that the object retains a
1863
        // sensible value.
1864
        val = (cdl_int) 0;
1865
        valuable->set(transaction, val, CdlValueSource_Default);
1866
    }
1867
 
1868
    CYG_UNUSED_PARAM(CdlNode, dest);
1869
    CYG_REPORT_RETURN();
1870
}
1871
 
1872
int
1873
CdlValuableBody::parse_default_value(CdlInterpreter interp, int argc, const char* argv[])
1874
{
1875
    CYG_REPORT_FUNCNAMETYPE("parse_default_value", "result %d");
1876
    int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_DefaultValue, 0, 0,
1877
                                                     &default_value_update_handler);
1878
    CYG_REPORT_RETVAL(result);
1879
    return result;
1880
}
1881
 
1882
bool
1883
CdlValuableBody::has_default_value_expression() const
1884
{
1885
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_default_value_expression", "result %d");
1886
    CYG_REPORT_FUNCARG1XV(this);
1887
    CYG_PRECONDITION_THISC();
1888
 
1889
    bool result = has_property(CdlPropertyId_DefaultValue);
1890
    CYG_REPORT_RETVAL(result);
1891
    return result;
1892
}
1893
 
1894
CdlProperty_Expression
1895
CdlValuableBody::get_default_value_expression() const
1896
{
1897
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_default_value_expression", "result %");
1898
    CYG_REPORT_FUNCARG1XV(this);
1899
    CYG_PRECONDITION_THISC();
1900
 
1901
    CdlProperty_Expression result = 0;
1902
    CdlProperty property          = get_property(CdlPropertyId_DefaultValue);
1903
    if (0 != property) {
1904
        result = dynamic_cast<CdlProperty_Expression>(property);
1905
        CYG_ASSERTC(0 != result);
1906
    }
1907
 
1908
    CYG_REPORT_RETVAL(result);
1909
    return result;
1910
}
1911
 
1912
//}}}
1913
//{{{  calculated_property              
1914
 
1915
// ----------------------------------------------------------------------------
1916
// Syntax: calculated <expression>
1917
 
1918
void
1919
CdlValuableBody::calculated_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1920
                                           CdlUpdate change)
1921
{
1922
    CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1923
    CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1924
 
1925
    // Loaded and unloading should be ignored.
1926
    if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1927
        CYG_REPORT_RETURN();
1928
        return;
1929
    }
1930
 
1931
    // Init, Created, Destroyed, ValueChange and ActiveChange should
1932
    // all result in the expression being re-evaluated and the result
1933
    // applied.
1934
    CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1935
    CYG_ASSERTC(0 != valuable);
1936
    CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1937
    CYG_ASSERTC(0 != expr);
1938
 
1939
    CdlSimpleValue val;
1940
 
1941
    try {
1942
 
1943
        CdlEvalContext context(transaction, source, prop);
1944
        expr->eval(context, val);
1945
 
1946
        valuable->set(transaction, val, CdlValueSource_Default);
1947
 
1948
    } catch(CdlEvalException e) {
1949
 
1950
 
1951
        // An EvalException conflict will have been created, so the
1952
        // user knows that this default_value is not kosher. It is
1953
        // still a good idea to make sure that the object retains a
1954
        // sensible value.
1955
        val = (cdl_int) 0;
1956
        valuable->set(transaction, val, CdlValueSource_Default);
1957
    }
1958
 
1959
    CYG_UNUSED_PARAM(CdlNode, dest);
1960
    CYG_REPORT_RETURN();
1961
}
1962
 
1963
// FIXME: check for flavor none?
1964
int
1965
CdlValuableBody::parse_calculated(CdlInterpreter interp, int argc, const char* argv[])
1966
{
1967
    CYG_REPORT_FUNCNAMETYPE("parse_calculated", "result %d");
1968
 
1969
    int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_Calculated, 0, 0,
1970
                                                     &calculated_update_handler);
1971
    CYG_REPORT_RETVAL(result);
1972
    return result;
1973
}
1974
 
1975
bool
1976
CdlValuableBody::has_calculated_expression() const
1977
{
1978
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_calculated_expression", "result %d");
1979
    CYG_REPORT_FUNCARG1XV(this);
1980
    CYG_PRECONDITION_THISC();
1981
 
1982
    bool result = has_property(CdlPropertyId_Calculated);
1983
    CYG_REPORT_RETVAL(result);
1984
    return result;
1985
}
1986
 
1987
CdlProperty_Expression
1988
CdlValuableBody::get_calculated_expression() const
1989
{
1990
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_calculated_expression", "result %p");
1991
    CYG_REPORT_FUNCARG1XV(this);
1992
    CYG_PRECONDITION_THISC();
1993
 
1994
    CdlProperty_Expression result   = 0;
1995
    CdlProperty            property = get_property(CdlPropertyId_Calculated);
1996
    if (0 != property) {
1997
        result = dynamic_cast<CdlProperty_Expression>(property);
1998
        CYG_ASSERTC(0 != result);
1999
    }
2000
 
2001
    CYG_REPORT_RETVAL(result);
2002
    return result;
2003
}
2004
 
2005
//}}}
2006
//{{{  active_if property               
2007
 
2008
// ----------------------------------------------------------------------------
2009
// Syntax:
2010
//    active_if <goal expression>
2011
 
2012
void
2013
CdlValuableBody::active_if_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2014
                                      CdlUpdate change)
2015
{
2016
    CYG_REPORT_FUNCNAME("CdlValuable::active_if_update_handler");
2017
    CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2018
    CYG_PRECONDITION_CLASSC(transaction);
2019
    CYG_PRECONDITION_CLASSC(source);
2020
    CYG_PRECONDITION_CLASSC(prop);
2021
 
2022
    // Loaded should be ignored here, the world is still getting sorted out.
2023
    // Unloading is of no interest, the source is disappearing anyway.
2024
    if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2025
        CYG_REPORT_RETURN();
2026
        return;
2027
    }
2028
 
2029
    // Any other change warrants re-evaluating the active status of the source.
2030
    // This can be achieved via a test_active() call, although that may do
2031
    // more work than is strictly necessary e.g. it may re-evaluate other
2032
    // is_active properties. In practice it is unlikely that there will
2033
    // be enough other constraints to warrant more efficient processing.
2034
    bool old_state = transaction->is_active(source);
2035
    bool new_state = source->test_active(transaction);
2036
    if (old_state != new_state) {
2037
        transaction->set_active(source, new_state);
2038
    }
2039
 
2040
    CYG_UNUSED_PARAM(CdlNode, dest);
2041
    CYG_REPORT_RETURN();
2042
}
2043
 
2044
int
2045
CdlValuableBody::parse_active_if(CdlInterpreter interp, int argc, const char* argv[])
2046
{
2047
    CYG_REPORT_FUNCNAMETYPE("parse_active_if", "result %d");
2048
 
2049
    int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_ActiveIf, 0, 0,
2050
                                                         &active_if_update_handler);
2051
    CYG_REPORT_RETVAL(result);
2052
    return result;
2053
}
2054
 
2055
bool
2056
CdlValuableBody::has_active_if_conditions() const
2057
{
2058
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_active_if_conditions", "result %d");
2059
    CYG_REPORT_FUNCARG1XV(this);
2060
    CYG_PRECONDITION_THISC();
2061
 
2062
    bool result = has_property(CdlPropertyId_ActiveIf);
2063
    CYG_REPORT_RETVAL(result);
2064
    return result;
2065
}
2066
 
2067
void
2068
CdlValuableBody::get_active_if_conditions(std::vector<CdlProperty_GoalExpression>& result) const
2069
{
2070
    CYG_REPORT_FUNCNAME("CdlValuable::get_active_if_conditions");
2071
    CYG_REPORT_FUNCARG1XV(this);
2072
    CYG_PRECONDITION_THISC();
2073
 
2074
    std::vector<CdlProperty> properties;
2075
    get_properties(CdlPropertyId_ActiveIf, properties);
2076
    std::vector<CdlProperty>::const_iterator i;
2077
    for (i = properties.begin(); i != properties.end(); i++) {
2078
        CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2079
        CYG_ASSERTC(0 != goal);
2080
        result.push_back(goal);
2081
    }
2082
 
2083
    CYG_REPORT_RETURN();
2084
}
2085
 
2086
//}}}
2087
//{{{  requires property                
2088
 
2089
// ----------------------------------------------------------------------------
2090
// Syntax: requires <goal expression>
2091
 
2092
void
2093
CdlValuableBody::requires_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2094
                                         CdlUpdate change)
2095
{
2096
    CYG_REPORT_FUNCNAME("CdlValuable::requires_update_handler");
2097
    CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2098
    CYG_PRECONDITION_CLASSC(transaction);
2099
 
2100
    // Loaded and Unloading are not of interest.
2101
    if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2102
        CYG_REPORT_RETURN();
2103
        return;
2104
    }
2105
 
2106
    // Any other change should cause normal handling. This happens in
2107
    // a separate function because "requires" properties also need to
2108
    // be checked when e.g. the source becomes inactive.
2109
    CdlValuable valuable = dynamic_cast<CdlValuable>(source);
2110
    CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(prop);
2111
    CYG_ASSERT_CLASSC(valuable);
2112
    CYG_ASSERT_CLASSC(gexpr);
2113
 
2114
    valuable->check_requires(transaction, gexpr);
2115
 
2116
    CYG_UNUSED_PARAM(CdlNode, dest);
2117
    CYG_REPORT_RETURN();
2118
}
2119
 
2120
int
2121
CdlValuableBody::parse_requires(CdlInterpreter interp, int argc, const char* argv[])
2122
{
2123
    CYG_REPORT_FUNCNAMETYPE("parse_requires", "result %d");
2124
 
2125
    int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_Requires, 0, 0,
2126
                                                         &requires_update_handler);
2127
    CYG_REPORT_RETVAL(result);
2128
    return result;
2129
}
2130
 
2131
bool
2132
CdlValuableBody::has_requires_goals() const
2133
{
2134
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_requires_goals", "result %d");
2135
    CYG_REPORT_FUNCARG1XV(this);
2136
    CYG_PRECONDITION_THISC();
2137
 
2138
    bool result = has_property(CdlPropertyId_Requires);
2139
    CYG_REPORT_RETVAL(result);
2140
    return result;
2141
}
2142
 
2143
void
2144
CdlValuableBody::get_requires_goals(std::vector<CdlProperty_GoalExpression>& result) const
2145
{
2146
    CYG_REPORT_FUNCNAME("CdlValuable::get_requires_goals");
2147
    CYG_REPORT_FUNCARG1XV(this);
2148
    CYG_PRECONDITION_THISC();
2149
 
2150
    std::vector<CdlProperty> properties;
2151
    get_properties(CdlPropertyId_Requires, properties);
2152
    std::vector<CdlProperty>::const_iterator i;
2153
    for (i = properties.begin(); i != properties.end(); i++) {
2154
        CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2155
        CYG_ASSERTC(0 != goal);
2156
        result.push_back(goal);
2157
    }
2158
 
2159
    CYG_REPORT_RETURN();
2160
}
2161
 
2162
//}}}
2163
//{{{  implements property              
2164
 
2165
// ----------------------------------------------------------------------------
2166
// Syntax: implements <reference to interface>
2167
 
2168
void
2169
CdlValuableBody::implements_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2170
                                           CdlUpdate change)
2171
{
2172
    CYG_REPORT_FUNCNAME("CdlValuable::implements_update_handler");
2173
    CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2174
    CYG_PRECONDITION_CLASSC(transaction);
2175
 
2176
    // Calculation of interface values happens inside
2177
    // CdlInterfaceBody::recalculate(). That member function simply
2178
    // checks all of the implementors and recalculates the value from
2179
    // scratch. It needs to be invoked whenever there is a relevant
2180
    // change to the implementors. Currently no attempt is made to
2181
    // optimise interface updates, although this may have to change in
2182
    // future.
2183
 
2184
    // Any changes to the interface itself can be ignored.
2185
    if ((CdlUpdate_ValueChange == change) || (CdlUpdate_ActiveChange == change)) {
2186
        CYG_REPORT_RETURN();
2187
        return;
2188
    }
2189
 
2190
    // The second stage init is irrelevant
2191
    if (CdlUpdate_Init == change) {
2192
        CYG_REPORT_RETURN();
2193
        return;
2194
    }
2195
 
2196
    // Possibilities:
2197
    // 1) source is being loaded, dest valid
2198
    // 2) source is being loaded, dest unknown
2199
    // 3) source is being unloaded, dest valid
2200
    // 4) source is being unloaded, dest unknown
2201
    // 5) dest has been created
2202
    // 6) dest is going away
2203
    //
2204
    // If we have a valid dest, it needs to be updated and any structural
2205
    // conflicts have to be cleared.
2206
    //
2207
    // If there is no dest, the implements property remains unbound.
2208
    // A suitable conflict is created in the base class.
2209
    //
2210
    // If the dest is invalid, a structural conflict has to be created.
2211
    if (CdlUpdate_Destroyed == change) {
2212
        // There is no need to do any clean-ups in the dest.
2213
        dest = 0;
2214
    }
2215
    if (0 == dest) {
2216
        transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2217
    } else {
2218
        CdlInterface interface = dynamic_cast<CdlInterface>(dest);
2219
 
2220
        if (0 == interface) {
2221
            std::string msg = source->get_class_name() + " " + source->get_name() + " cannot implement " +
2222
                dest->get_name() + "\n    The latter is not an interface.";
2223
            CdlConflict_DataBody::make(transaction, source, prop, msg);
2224
        } else {
2225
            transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
2226
            interface->recalculate(transaction);
2227
        }
2228
    }
2229
 
2230
    CYG_REPORT_RETURN();
2231
}
2232
 
2233
int
2234
CdlValuableBody::parse_implements(CdlInterpreter interp, int argc, const char* argv[])
2235
{
2236
    CYG_REPORT_FUNCNAMETYPE("parse_implements", "result %d");
2237
 
2238
    int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Implements, 0, 0, false,
2239
                                                    &implements_update_handler);
2240
 
2241
    CYG_REPORT_RETVAL(result);
2242
    return result;
2243
}
2244
 
2245
void
2246
CdlValuableBody::get_implemented_interfaces(std::vector<CdlInterface>& result) const
2247
{
2248
    CYG_REPORT_FUNCNAME("CdlValuable::get_implemented_interfaces");
2249
    CYG_REPORT_FUNCARG1XV(this);
2250
    CYG_PRECONDITION_THISC();
2251
 
2252
    std::vector<CdlProperty> properties;
2253
    get_properties(CdlPropertyId_Implements, properties);
2254
    std::vector<CdlProperty>::const_iterator i;
2255
    for (i = properties.begin(); i != properties.end(); i++) {
2256
        CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*i);
2257
        CYG_ASSERTC(0 != refprop);
2258
        CdlNode node = refprop->get_destination();
2259
        if (0 != node) {
2260
            CdlInterface interface = dynamic_cast<CdlInterface>(node);
2261
            CYG_ASSERT_CLASSC(interface);
2262
            result.push_back(interface);
2263
        }
2264
    }
2265
 
2266
    CYG_REPORT_RETURN();
2267
}
2268
 
2269
//}}}
2270
//{{{  Other properties                 
2271
 
2272
// ----------------------------------------------------------------------------
2273
// Syntax: flavor <legal flavor>
2274
 
2275
static void
2276
parse_flavor_final_check(CdlInterpreter interp, CdlProperty_String prop)
2277
{
2278
    CYG_REPORT_FUNCNAME("parse_flavor_final_check");
2279
    CYG_PRECONDITION_CLASSC(interp);
2280
    CYG_PRECONDITION_CLASSC(prop);
2281
 
2282
    const std::string& str = prop->get_string();
2283
    std::string copy = std::string(str);
2284
    CdlValueFlavor flavor;
2285
 
2286
    if (!Cdl::string_to_flavor(copy, flavor)) {
2287
        CdlParse::report_property_parse_error(interp, prop, str + " is not a valid CDL flavor.");
2288
    }
2289
 
2290
    CYG_REPORT_RETURN();
2291
}
2292
 
2293
 
2294
int
2295
CdlValuableBody::parse_flavor(CdlInterpreter interp, int argc, const char* argv[])
2296
{
2297
    CYG_REPORT_FUNCNAMETYPE("parse_flavor", "result %d");
2298
 
2299
    int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Flavor, 0, &parse_flavor_final_check);
2300
    CYG_REPORT_RETVAL(result);
2301
    return result;
2302
}
2303
 
2304
// ----------------------------------------------------------------------------
2305
// syntax: group <group name>
2306
int
2307
CdlValuableBody::parse_group(CdlInterpreter interp, int argc, const char* argv[])
2308
{
2309
    CYG_REPORT_FUNCNAMETYPE("parse_group", "result %d");
2310
 
2311
    int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Group, 0, 0);
2312
 
2313
    CYG_REPORT_RETVAL(result);
2314
    return result;
2315
}
2316
 
2317
// ----------------------------------------------------------------------------
2318
// Syntax: check_proc <tclcode>
2319
 
2320
int
2321
CdlValuableBody::parse_check_proc(CdlInterpreter interp, int argc, const char* argv[])
2322
{
2323
    CYG_REPORT_FUNCNAMETYPE("parse_check_proc", "result %d");
2324
 
2325
    int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_CheckProc, 0, 0);
2326
 
2327
    CYG_REPORT_RETVAL(result);
2328
    return result;
2329
}
2330
 
2331
bool
2332
CdlValuableBody::has_check_proc() const
2333
{
2334
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_check_proc", "result %d");
2335
    CYG_REPORT_FUNCARG1XV(this);
2336
    CYG_PRECONDITION_THISC();
2337
 
2338
    bool result = has_property(CdlPropertyId_CheckProc);
2339
    CYG_REPORT_RETVAL(result);
2340
    return result;
2341
}
2342
 
2343
cdl_tcl_code
2344
CdlValuableBody::get_check_proc() const
2345
{
2346
    CYG_REPORT_FUNCNAME("CdlValuable::get_check_proc");
2347
    CYG_REPORT_FUNCARG1XV(this);
2348
    CYG_PRECONDITION_THISC();
2349
 
2350
    cdl_tcl_code result         = "";
2351
    CdlProperty  property       = get_property(CdlPropertyId_CheckProc);
2352
    if (0 != property) {
2353
        CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2354
        CYG_ASSERTC(0 != code_prop);
2355
        result = code_prop->get_code();
2356
    }
2357
 
2358
    CYG_REPORT_RETURN();
2359
    return result;
2360
}
2361
 
2362
// ----------------------------------------------------------------------------
2363
// Syntax: entry_proc <tclcode>
2364
 
2365
int
2366
CdlValuableBody::parse_entry_proc(CdlInterpreter interp, int argc, const char* argv[])
2367
{
2368
    CYG_REPORT_FUNCNAMETYPE("parse_entry_proc", "result %d");
2369
 
2370
    int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_EntryProc, 0, 0);
2371
 
2372
    CYG_REPORT_RETVAL(result);
2373
    return result;
2374
}
2375
 
2376
bool
2377
CdlValuableBody::has_entry_proc() const
2378
{
2379
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_entry_proc", "result %d");
2380
    CYG_REPORT_FUNCARG1XV(this);
2381
    CYG_PRECONDITION_THISC();
2382
 
2383
    bool result = has_property(CdlPropertyId_EntryProc);
2384
    CYG_REPORT_RETVAL(result);
2385
    return result;
2386
}
2387
cdl_tcl_code
2388
CdlValuableBody::get_entry_proc() const
2389
{
2390
    CYG_REPORT_FUNCNAME("CdlValuable::get_entry_proc");
2391
    CYG_REPORT_FUNCARG1XV(this);
2392
    CYG_PRECONDITION_THISC();
2393
 
2394
    cdl_tcl_code result         = "";
2395
    CdlProperty  property       = get_property(CdlPropertyId_EntryProc);
2396
    if (0 != property) {
2397
        CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2398
        CYG_ASSERTC(0 != code_prop);
2399
        result = code_prop->get_code();
2400
    }
2401
 
2402
    CYG_REPORT_RETURN();
2403
    return result;
2404
}
2405
 
2406
//}}}
2407
 
2408
//{{{  CdlValuable misc                 
2409
 
2410
// ----------------------------------------------------------------------------
2411
// Objects with flavor none are not modifiable. Also, objects with the
2412
// calculated property are not modifiable. Everything else is ok.
2413
 
2414
bool
2415
CdlValuableBody::is_modifiable() const
2416
{
2417
    CYG_REPORT_FUNCNAMETYPE("CdlValuableBody::is_modifiable", "result %d");
2418
    CYG_REPORT_FUNCARG1XV(this);
2419
    CYG_PRECONDITION_THISC();
2420
 
2421
    bool result = true;
2422
    if (CdlValueFlavor_None == get_flavor()) {
2423
        result = false;
2424
    } else if (has_property(CdlPropertyId_Calculated)) {
2425
        result = false;
2426
    }
2427
 
2428
    CYG_REPORT_RETVAL(result);
2429
    return result;
2430
}
2431
 
2432
//}}}
2433
//{{{  CdlValuable::get_widget_hint()   
2434
 
2435
// ----------------------------------------------------------------------------
2436
 
2437
void
2438
CdlValuableBody::get_widget_hint(CdlWidgetHint& hint)
2439
{
2440
    CYG_REPORT_FUNCNAME("CdlValuable::get_widget_hint");
2441
    CYG_REPORT_FUNCARG2XV(this, &hint);
2442
    CYG_PRECONDITION_THISC();
2443
 
2444
    // Start by resetting the hint to default values.
2445
    hint.bool_widget  = CdlBoolWidget_None;
2446
    hint.value_widget = CdlValueWidget_None;
2447
    hint.radio_button_interface = "";
2448
 
2449
    // If the valuable is a loadable then it cannot be modified directly.
2450
    // Changing the value means unloading and/or loading more data
2451
    // into the configuration. This should always be handled via a
2452
    // separate dialog, followed by a tree redisplay
2453
    CdlConstLoadable loadable = dynamic_cast<CdlConstLoadable>(this);
2454
    if (0 != loadable) {
2455
        hint.value_widget = CdlValueWidget_Loadable;
2456
        CYG_REPORT_RETURN();
2457
        return;
2458
    }
2459
 
2460
    // If the valuable is not modifiable then we are already done.
2461
    CdlValueFlavor flavor = this->get_flavor();
2462
    if ((CdlValueFlavor_None == flavor) || !this->is_modifiable()) {
2463
        CYG_REPORT_RETURN();
2464
        return;
2465
    }
2466
 
2467
    // If there is a custom dialog and dialogs are enabled, use it.
2468
    if (this->has_dialog() && CdlDialogBody::dialogs_are_enabled()) {
2469
        if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2470
            hint.bool_widget = CdlBoolWidget_CustomDialog;
2471
        }
2472
        if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2473
            hint.value_widget = CdlValueWidget_CustomDialog;
2474
        }
2475
        CYG_REPORT_RETURN();
2476
        return;
2477
    }
2478
 
2479
    // Process the bool part, if any
2480
    if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2481
 
2482
        // Default to a CheckButton
2483
        hint.bool_widget = CdlBoolWidget_CheckButton;
2484
 
2485
        // Under some circumstances it is appropriate to use a radio button instead.
2486
        // This is the case when there are several mutually exclusive entities.
2487
        // Most of the time radio buttons should actually be handled by a single
2488
        // option which has a list of legal values. There are a couple of cases
2489
        // where this is not appropriate:
2490
        //
2491
        // 1) grouping. Some of the mutually exclusive entities could be containers.
2492
        //    With clever use of a single option and some active_if properties it
2493
        //    would be possible to get almost the same effect, but not quite.
2494
        //
2495
        // 2) external packages. It should be possible to have a third party package
2496
        //    which could add e.g. a new scheduler.
2497
        //
2498
        // The implementation of this involves interfaces. Basically mutually
2499
        // exclusive entities should implement the same interface, and that
2500
        // interface should have an explicit requires $cdl_value == 1
2501
        // In addition all of the options involved should have the same parent.
2502
        // An entity may implement multiple interfaces, so they all have to be checked
2503
        CdlInterface radio_interface = 0;
2504
        std::vector<CdlProperty> implements = this->get_properties(CdlPropertyId_Implements);
2505
        std::vector<CdlProperty>::const_iterator imp_i;
2506
        for (imp_i = implements.begin(); (imp_i != implements.end()) && (0 == radio_interface); imp_i++) {
2507
            CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*imp_i);
2508
            CYG_ASSERT_CLASSC(refprop);
2509
 
2510
            CdlNode destnode = refprop->get_destination();
2511
            if (0 == destnode) {
2512
                continue;
2513
            }
2514
            CdlInterface interface = dynamic_cast<CdlInterface>(destnode);
2515
            CYG_ASSERT_CLASSC(interface);
2516
 
2517
            std::vector<CdlProperty_GoalExpression> requires;
2518
            std::vector<CdlProperty_GoalExpression>::const_iterator req_i;
2519
            interface->get_requires_goals(requires);
2520
            for (req_i = requires.begin(); req_i != requires.end(); req_i++) {
2521
 
2522
                CdlExpression expr = (*req_i)->get_expression();
2523
                CdlSubexpression& subexpr = expr->sub_expressions[expr->first_subexpression];
2524
                if (CdlExprOp_Equal != subexpr.op) {
2525
                    continue;
2526
                }
2527
 
2528
                CdlSubexpression& lhs = expr->sub_expressions[subexpr.lhs_index];
2529
                CdlSubexpression& rhs = expr->sub_expressions[subexpr.rhs_index];
2530
                CdlSubexpression* ref_operand = &lhs;
2531
 
2532
                // Allow for "a == 1" or "1 == a"
2533
                if ((CdlExprOp_IntegerConstant == lhs.op) && (1 == lhs.constants.get_integer_value())) {
2534
                    ref_operand = &rhs;
2535
                } else if ((CdlExprOp_IntegerConstant == rhs.op) && (1 == rhs.constants.get_integer_value())) {
2536
                    ref_operand = &lhs;
2537
                } else {
2538
                    continue;
2539
                }
2540
 
2541
                if (CdlExprOp_Reference != ref_operand->op) {
2542
                    continue;
2543
                }
2544
                CdlReference& ref = expr->references[ref_operand->reference_index];
2545
                if (ref.get_destination() == interface) {
2546
                    break;
2547
                }
2548
            }
2549
            if (req_i == requires.end()) {
2550
                continue;
2551
            }
2552
 
2553
            CdlContainer parent = this->get_parent();
2554
            CYG_ASSERT_CLASSC(parent);
2555
 
2556
            std::vector<CdlValuable> implementers;
2557
            std::vector<CdlValuable>::const_iterator imp_i;
2558
            interface->get_implementers(implementers);
2559
            for (imp_i = implementers.begin(); imp_i != implementers.end(); imp_i++) {
2560
                if (parent != (*imp_i)->get_parent()) {
2561
                    break;
2562
                }
2563
            }
2564
 
2565
            if (imp_i == implementers.end()) {
2566
                // An interface has been found that matches the constraints.
2567
                radio_interface = interface;
2568
            }
2569
        }
2570
        if (0 != radio_interface) {
2571
            hint.bool_widget = CdlBoolWidget_Radio;
2572
            hint.radio_button_interface = radio_interface->get_name();
2573
        }
2574
    }
2575
 
2576
    // Process the data part, if any
2577
    if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2578
 
2579
        // Default to a simple entry box.
2580
        hint.value_widget = CdlValueWidget_EntryBox;
2581
 
2582
        // If there is a legal_values list, this will normally indicate
2583
        // which widget should be used.
2584
        if (this->has_legal_values()) {
2585
            // The legal_values expression needs to be evaluated and examined.
2586
            // If the result is a simple numerical range then all we need to
2587
            // figure out is whether to default to decimal, hex, octal or double.
2588
            // Otherwise if the result is a simple list and all of the entries
2589
            // are numerical, that is sufficient information. If a list with
2590
            // non-numerical entries that is fine as well. Anything more complicated
2591
            // needs to revert to an entry box.
2592
            CdlProperty_ListExpression lexpr = this->get_legal_values();
2593
            CdlEvalContext             context(0, this, lexpr);
2594
            CdlListValue               val;
2595
 
2596
            try {
2597
                lexpr->eval(context, val);
2598
                const std::vector<CdlSimpleValue>& table = val.get_table();
2599
                const std::vector<std::pair<cdl_int, cdl_int> >& int_ranges = val.get_integer_ranges();
2600
                const std::vector<std::pair<double, double> >&   double_ranges = val.get_double_ranges();
2601
 
2602
                if ((0 == table.size()) && (0 == int_ranges.size()) && (1 == double_ranges.size())) {
2603
 
2604
                    // A straightforward range of double precision numbers
2605
                    hint.value_widget = CdlValueWidget_DoubleRange;
2606
 
2607
                } else if ((0 == table.size()) && (1 == int_ranges.size()) && (0 == double_ranges.size())) {
2608
 
2609
                    // Bummer. The formatting information has been lost.
2610
                    // To fix this the two sets of ranges should be collapsed into pairs of
2611
                    // CdlSimpleValue's.
2612
                    hint.value_widget = CdlValueWidget_DecimalRange;
2613
 
2614
                } else if ((1 <= table.size() && (0 == int_ranges.size()) && (0 == double_ranges.size()))) {
2615
 
2616
                    // If all of the values are numerical, then we have a numeric set.
2617
                    // Otherwise we have a string set.
2618
                    bool all_numeric = true;
2619
                    std::vector<CdlSimpleValue>::const_iterator tab_i;
2620
                    for (tab_i = table.begin(); (tab_i != table.end()) && all_numeric; tab_i++) {
2621
                        if (!tab_i->has_double_value() && !tab_i->has_integer_value()) {
2622
                            all_numeric = false;
2623
                        }
2624
                    }
2625
                    if (all_numeric) {
2626
                        hint.value_widget = CdlValueWidget_NumericSet;
2627
                    } else {
2628
                        hint.value_widget = CdlValueWidget_StringSet;
2629
                    }
2630
 
2631
                } else {
2632
                    // The list expression is a complex combination. Leave it as an entry box.
2633
                    // In some cases it would be possible to do better, for example
2634
                    //     legal_values -1 1 to 4 8 to 12
2635
                    // Support for cases like these may get added in future, if such cases
2636
                    // ever arise in practice.
2637
                }
2638
 
2639
            } catch(...) {
2640
                // Not a lot that can be done here, unfortunately
2641
            }
2642
        } else {
2643
            // There is no legal_values property, so an entry box is probably the
2644
            // right thing to use. There is a special case for multiline strings,
2645
            // identified by a default_value expression that contains a newline.
2646
            if (this->has_default_value_expression()) {
2647
                CdlProperty_Expression expr = this->get_default_value_expression();
2648
                CdlEvalContext         context(0, this, expr);
2649
                CdlSimpleValue         val;
2650
                try {
2651
                    expr->eval(context, val);
2652
                    std::string tmp = val.get_value();
2653
                    if (std::string::npos != tmp.find('\n')) {
2654
                        hint.value_widget = CdlValueWidget_MultilineString;
2655
                    }
2656
                } catch(...) {
2657
                    // Not a lot that can be done here, unfortunately
2658
                }
2659
            }
2660
        }
2661
    }
2662
 
2663
    CYG_REPORT_RETURN();
2664
}
2665
 
2666
//}}}
2667
//{{{  CdlValuable get operations       
2668
 
2669
// ----------------------------------------------------------------------------
2670
const CdlValue&
2671
CdlValuableBody::get_whole_value() const
2672
{
2673
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_whole_value", "result %p");
2674
    CYG_REPORT_FUNCARG1XV(this);
2675
    CYG_PRECONDITION_THISC();
2676
 
2677
    CYG_REPORT_RETVAL(&value);
2678
    return value;
2679
}
2680
 
2681
CdlValueFlavor
2682
CdlValuableBody::get_flavor() const
2683
{
2684
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_flavor", "result %d");
2685
    CYG_REPORT_FUNCARG1XV(this);
2686
    CYG_PRECONDITION_THISC();
2687
 
2688
    CdlValueFlavor result = value.get_flavor();
2689
    CYG_REPORT_RETVAL((int) result);
2690
    return result;
2691
}
2692
 
2693
CdlValueSource
2694
CdlValuableBody::get_source() const
2695
{
2696
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2697
    CYG_REPORT_FUNCARG1XV(this);
2698
    CYG_PRECONDITION_THISC();
2699
 
2700
    CdlValueSource result = value.get_source();
2701
    CYG_REPORT_RETVAL((int) result);
2702
    return result;
2703
}
2704
 
2705
bool
2706
CdlValuableBody::has_source(CdlValueSource source) const
2707
{
2708
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2709
    CYG_REPORT_FUNCARG2XV(this, source);
2710
    CYG_PRECONDITION_THISC();
2711
 
2712
    bool result = value.has_source(source);
2713
    CYG_REPORT_RETVAL(result);
2714
    return result;
2715
}
2716
 
2717
bool
2718
CdlValuableBody::is_enabled(CdlValueSource source) const
2719
{
2720
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2721
    CYG_REPORT_FUNCARG2XV(this, source);
2722
    CYG_PRECONDITION_THISC();
2723
 
2724
    bool result = value.is_enabled(source);
2725
    CYG_REPORT_RETVAL(result);
2726
    return result;
2727
}
2728
 
2729
std::string
2730
CdlValuableBody::get_value(CdlValueSource source) const
2731
{
2732
    CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2733
    CYG_REPORT_FUNCARG2XV(this, source);
2734
    CYG_PRECONDITION_THISC();
2735
 
2736
    std::string result = value.get_value(source);
2737
    CYG_REPORT_RETURN();
2738
    return result;
2739
}
2740
 
2741
bool
2742
CdlValuableBody::has_integer_value(CdlValueSource source) const
2743
{
2744
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2745
    CYG_REPORT_FUNCARG2XV(this, source);
2746
    CYG_PRECONDITION_THISC();
2747
 
2748
    bool result = value.has_integer_value(source);
2749
    CYG_REPORT_RETVAL(result);
2750
    return result;
2751
}
2752
 
2753
cdl_int
2754
CdlValuableBody::get_integer_value(CdlValueSource source) const
2755
{
2756
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2757
    CYG_REPORT_FUNCARG2XV(this, source);
2758
    CYG_PRECONDITION_THISC();
2759
 
2760
    cdl_int result = value.get_integer_value(source);
2761
    CYG_REPORT_RETVAL((int) result);
2762
    return result;
2763
}
2764
 
2765
bool
2766
CdlValuableBody::has_double_value(CdlValueSource source) const
2767
{
2768
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2769
    CYG_REPORT_FUNCARG2XV(this, source);
2770
    CYG_PRECONDITION_THISC();
2771
 
2772
    bool result = value.has_double_value(source);
2773
    CYG_REPORT_RETVAL(result);
2774
    return result;
2775
}
2776
 
2777
double
2778
CdlValuableBody::get_double_value(CdlValueSource source) const
2779
{
2780
    CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2781
    CYG_REPORT_FUNCARG2XV(this, source);
2782
    CYG_PRECONDITION_THISC();
2783
 
2784
    double result = value.get_double_value();
2785
    CYG_REPORT_RETURN();
2786
    return result;
2787
}
2788
 
2789
CdlSimpleValue
2790
CdlValuableBody::get_simple_value(CdlValueSource source) const
2791
{
2792
    CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2793
    CYG_REPORT_FUNCARG2XV(this, source);
2794
    CYG_PRECONDITION_THISC();
2795
 
2796
    CdlSimpleValue result = value.get_simple_value(source);
2797
    CYG_REPORT_RETURN();
2798
    return result;
2799
}
2800
 
2801
// ----------------------------------------------------------------------------
2802
CdlValueSource
2803
CdlValuableBody::get_source(CdlTransaction transaction) const
2804
{
2805
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2806
    CYG_REPORT_FUNCARG2XV(this, transaction);
2807
    CYG_PRECONDITION_THISC();
2808
    CYG_PRECONDITION_CLASSC(transaction);
2809
 
2810
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2811
    CdlValueSource result = transaction_value.get_source();
2812
    CYG_REPORT_RETVAL((int) result);
2813
    return result;
2814
}
2815
 
2816
bool
2817
CdlValuableBody::has_source(CdlTransaction transaction, CdlValueSource source) const
2818
{
2819
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2820
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2821
    CYG_PRECONDITION_THISC();
2822
    CYG_PRECONDITION_CLASSC(transaction);
2823
 
2824
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2825
    bool result = transaction_value.has_source(source);
2826
    CYG_REPORT_RETVAL(result);
2827
    return result;
2828
}
2829
 
2830
bool
2831
CdlValuableBody::is_enabled(CdlTransaction transaction, CdlValueSource source) const
2832
{
2833
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2834
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2835
    CYG_PRECONDITION_THISC();
2836
    CYG_PRECONDITION_CLASSC(transaction);
2837
 
2838
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2839
    bool result = transaction_value.is_enabled(source);
2840
    CYG_REPORT_RETVAL(result);
2841
    return result;
2842
}
2843
 
2844
std::string
2845
CdlValuableBody::get_value(CdlTransaction transaction, CdlValueSource source) const
2846
{
2847
    CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2848
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2849
    CYG_PRECONDITION_THISC();
2850
    CYG_PRECONDITION_CLASSC(transaction);
2851
 
2852
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2853
    std::string result = transaction_value.get_value(source);
2854
    CYG_REPORT_RETURN();
2855
    return result;
2856
}
2857
 
2858
bool
2859
CdlValuableBody::has_integer_value(CdlTransaction transaction, CdlValueSource source) const
2860
{
2861
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2862
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2863
    CYG_PRECONDITION_THISC();
2864
    CYG_PRECONDITION_CLASSC(transaction);
2865
 
2866
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2867
    bool result = transaction_value.has_integer_value(source);
2868
    CYG_REPORT_RETVAL(result);
2869
    return result;
2870
}
2871
 
2872
cdl_int
2873
CdlValuableBody::get_integer_value(CdlTransaction transaction, CdlValueSource source) const
2874
{
2875
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2876
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2877
    CYG_PRECONDITION_THISC();
2878
    CYG_PRECONDITION_CLASSC(transaction);
2879
 
2880
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2881
    cdl_int result = transaction_value.get_integer_value(source);
2882
    CYG_REPORT_RETVAL((int) result);
2883
    return result;
2884
}
2885
 
2886
bool
2887
CdlValuableBody::has_double_value(CdlTransaction transaction, CdlValueSource source) const
2888
{
2889
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2890
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2891
    CYG_PRECONDITION_THISC();
2892
    CYG_PRECONDITION_CLASSC(transaction);
2893
 
2894
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2895
    bool result = transaction_value.has_double_value(source);
2896
    CYG_REPORT_RETVAL(result);
2897
    return result;
2898
}
2899
 
2900
double
2901
CdlValuableBody::get_double_value(CdlTransaction transaction, CdlValueSource source) const
2902
{
2903
    CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2904
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2905
    CYG_PRECONDITION_THISC();
2906
    CYG_PRECONDITION_CLASSC(transaction);
2907
 
2908
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2909
    double result = transaction_value.get_double_value();
2910
    CYG_REPORT_RETURN();
2911
    return result;
2912
}
2913
 
2914
CdlSimpleValue
2915
CdlValuableBody::get_simple_value(CdlTransaction transaction, CdlValueSource source) const
2916
{
2917
    CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2918
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
2919
    CYG_PRECONDITION_THISC();
2920
    CYG_PRECONDITION_CLASSC(transaction);
2921
 
2922
    const CdlValue& transaction_value = transaction->get_whole_value(this);
2923
    CdlSimpleValue result = transaction_value.get_simple_value(source);
2924
    CYG_REPORT_RETURN();
2925
    return result;
2926
}
2927
 
2928
//}}}
2929
//{{{  CdlValuable internal modify ops  
2930
 
2931
// ----------------------------------------------------------------------------
2932
// There has been a change to either the value itself or to the
2933
// set of legal values. It is necessary to validate the current
2934
// value, maintaining a suitable conflict object.
2935
void
2936
CdlValuableBody::check_value(CdlTransaction transaction)
2937
{
2938
    CYG_REPORT_FUNCNAME("CdlValuable::check_value");
2939
    CYG_REPORT_FUNCARG2XV(this, transaction);
2940
    CYG_PRECONDITION_THISC();
2941
    CYG_PRECONDITION_CLASSC(transaction);
2942
 
2943
    // Checking the value only makes sense for BoolData and Data
2944
    // values.
2945
    CdlValueFlavor flavor = value.get_flavor();
2946
    if ((CdlValueFlavor_BoolData != flavor) && (CdlValueFlavor_Data != flavor)) {
2947
        CYG_REPORT_RETURN();
2948
        return;
2949
    }
2950
 
2951
    // If the valuable is not currently active and enabled then it
2952
    // does not matter whether or not the value is legal. Any old
2953
    // conflicts should be destroyed.
2954
    if (!(transaction->is_active(this) && this->is_enabled(transaction))) {
2955
        transaction->clear_conflicts(this, &CdlConflict_IllegalValueBody::test);
2956
        CYG_REPORT_RETURN();
2957
        return;
2958
    }
2959
 
2960
    // If there is a legal_values property, check membership.
2961
    if (this->has_property(CdlPropertyId_LegalValues)) {
2962
        CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(get_property(CdlPropertyId_LegalValues));
2963
        CYG_ASSERT_CLASSC(lexpr);
2964
 
2965
        CdlSimpleValue val = this->get_simple_value(transaction);
2966
        CdlEvalContext context(transaction, this, lexpr);
2967
        try {
2968
            if (!lexpr->is_member(context, val)) {
2969
                if (!transaction->has_conflict(this, lexpr, &CdlConflict_IllegalValueBody::test)) {
2970
                    CdlConflict_IllegalValueBody::make(transaction, this, lexpr);
2971
                }
2972
 
2973
            } else {
2974
                // Tne current value is legal. Get rid of any old conflicts.
2975
                transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2976
            }
2977
        } catch(CdlEvalException e) {
2978
            // There should now be an EvalException conflict for this
2979
            // node, so there is no point in having an IllegalValue conflict
2980
            // as well.
2981
            transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2982
        }
2983
 
2984
        // FIXME: add support for check_proc
2985
    }
2986
 
2987
    CYG_REPORT_RETURN();
2988
}
2989
 
2990
// ----------------------------------------------------------------------------
2991
// There has been a change that may affect "requires" properties.
2992
// Again do the necessary checking and maintain suitable conflict
2993
// objects.
2994
void
2995
CdlValuableBody::check_requires(CdlTransaction transaction)
2996
{
2997
    CYG_REPORT_FUNCNAME("CdlValuable::check_requires");
2998
    CYG_REPORT_FUNCARG2XV(this, transaction);
2999
    CYG_PRECONDITION_THISC();
3000
    CYG_PRECONDITION_CLASSC(transaction);
3001
 
3002
    std::vector<CdlProperty> requires_properties;
3003
    std::vector<CdlProperty>::const_iterator prop_i;
3004
    get_properties(CdlPropertyId_Requires, requires_properties);
3005
    for (prop_i = requires_properties.begin(); prop_i != requires_properties.end(); prop_i++) {
3006
 
3007
        CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3008
        CYG_ASSERT_CLASSC(gexpr);
3009
        this->check_requires(transaction, gexpr);
3010
    }
3011
 
3012
    CYG_REPORT_RETURN();
3013
}
3014
 
3015
void
3016
CdlValuableBody::check_requires(CdlTransaction transaction, CdlProperty_GoalExpression gexpr)
3017
{
3018
    CYG_REPORT_FUNCNAME("CdlValuable::check_requires (property)");
3019
    CYG_REPORT_FUNCARG3XV(this, transaction, gexpr);
3020
    CYG_PRECONDITION_THISC();
3021
    CYG_PRECONDITION_CLASSC(transaction);
3022
    CYG_ASSERT_CLASSC(gexpr);
3023
 
3024
    // If the valuable is not currently active and enabled then the "requires"
3025
    // properties are irrelevant, and any old conflicts should be destroyed.
3026
    if (!transaction->is_active(this) || !this->is_enabled(transaction)) {
3027
        transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3028
        CYG_REPORT_RETURN();
3029
        return;
3030
    }
3031
 
3032
    // What is the current value of the goal expression?
3033
    try {
3034
        CdlEvalContext context(transaction, this, gexpr);
3035
        if (gexpr->eval(context)) {
3036
            // The goal is satisfied.
3037
            transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3038
        } else {
3039
            // The goal is not satisfied. Make sure there is a conflict object.
3040
            if (!transaction->has_conflict(this, gexpr, &CdlConflict_RequiresBody::test)) {
3041
                CdlConflict_RequiresBody::make(transaction, this, gexpr);
3042
            }
3043
        }
3044
    } catch(CdlEvalException e) {
3045
        // There should now be an EvalException conflict associated with this node,
3046
        // having a requires conflict as well serves no purpose
3047
        transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
3048
    }
3049
 
3050
    CYG_REPORT_RETURN();
3051
}
3052
 
3053
// ----------------------------------------------------------------------------
3054
// The update handler. If there is a change to the value or active state
3055
// then it is necessary to reevaluate any requires properties, and to
3056
// check whether or not the value is legal wrt legal_values etc.
3057
void
3058
CdlValuableBody::update(CdlTransaction transaction, CdlUpdate update)
3059
{
3060
    CYG_REPORT_FUNCNAME("CdlValuable::update");
3061
    CYG_REPORT_FUNCARG3XV(this, transaction, update);
3062
    CYG_PRECONDITION_THISC();
3063
    CYG_PRECONDITION_CLASSC(transaction);
3064
 
3065
    if ((CdlUpdate_ValueChange == update) || (CdlUpdate_ActiveChange == update)) {
3066
        this->check_value(transaction);
3067
        this->check_requires(transaction);
3068
    }
3069
 
3070
    CYG_REPORT_RETURN();
3071
}
3072
 
3073
// ----------------------------------------------------------------------------
3074
// Should this node be active. In addition to the base class' checks that
3075
// the parent is active and enabled, any active_if constraints need
3076
// to be evaluated.
3077
 
3078
bool
3079
CdlValuableBody::test_active(CdlTransaction transaction)
3080
{
3081
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::test_active", "result %d");
3082
    CYG_REPORT_FUNCARG2XV(this, transaction);
3083
    CYG_PRECONDITION_THISC();
3084
    CYG_PRECONDITION_CLASSC(transaction);
3085
 
3086
    bool result = true;
3087
    if (!this->CdlNodeBody::test_active(transaction)) {
3088
        result = false;
3089
    }
3090
 
3091
    if (result) {
3092
        std::vector<CdlProperty> active_if_properties;
3093
        std::vector<CdlProperty>::const_iterator prop_i;
3094
 
3095
        this->get_properties(CdlPropertyId_ActiveIf, active_if_properties);
3096
        for (prop_i = active_if_properties.begin(); result && (prop_i != active_if_properties.end()); prop_i++) {
3097
 
3098
            CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3099
            CYG_ASSERT_CLASSC(gexpr);
3100
            CdlEvalContext context(transaction, this, gexpr);
3101
            try {
3102
                if (!gexpr->eval(context)) {
3103
                    result = false;
3104
                }
3105
            } catch(CdlEvalException e) {
3106
                // Hmmm, an active_if property cannot be evaluated.
3107
                // Tricky. If the node is inactive then its conflicts
3108
                // are ignored, which would be a bad thing. For now
3109
                // assume that the node is active, unless it was already
3110
                // inactive for other reasons.
3111
            }
3112
        }
3113
    }
3114
 
3115
    CYG_REPORT_RETVAL(result);
3116
    return result;
3117
}
3118
 
3119
//}}}
3120
//{{{  CdlValuable modify operations    
3121
 
3122
// ----------------------------------------------------------------------------
3123
// Start with the non-transaction versions. These allocate a new transaction,
3124
// perform their operation in the context of that transaction, and then
3125
// commit the transaction.
3126
 
3127
void
3128
CdlValuableBody::set_source(CdlValueSource source)
3129
{
3130
    CYG_REPORT_FUNCNAME("CdlValuable::set_source (no transaction)");
3131
    CYG_REPORT_FUNCARG2XV(this, source);
3132
    CYG_PRECONDITION_THISC();
3133
 
3134
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3135
    this->set_source(transaction, source);
3136
    transaction->body();
3137
    delete transaction;
3138
 
3139
    CYG_REPORT_RETURN();
3140
}
3141
 
3142
void
3143
CdlValuableBody::invalidate_source(CdlValueSource source)
3144
{
3145
    CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source (no transaction)");
3146
    CYG_REPORT_FUNCARG2XV(this, source);
3147
    CYG_PRECONDITION_THISC();
3148
 
3149
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3150
    this->invalidate_source(transaction, source);
3151
    transaction->body();
3152
    delete transaction;
3153
 
3154
    CYG_REPORT_RETURN();
3155
}
3156
 
3157
void
3158
CdlValuableBody::set_enabled(bool val, CdlValueSource source)
3159
{
3160
    CYG_REPORT_FUNCNAME("CdlValuable::set_enabled (no transaction)");
3161
    CYG_REPORT_FUNCARG3XV(this, val, source);
3162
    CYG_PRECONDITION_THISC();
3163
 
3164
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3165
    this->set_enabled(transaction, val, source);
3166
    transaction->body();
3167
    delete transaction;
3168
 
3169
    CYG_REPORT_RETURN();
3170
}
3171
 
3172
void
3173
CdlValuableBody::set_value(CdlSimpleValue& val, CdlValueSource source)
3174
{
3175
    CYG_REPORT_FUNCNAME("CdlValuable::set_value (no transaction)");
3176
    CYG_REPORT_FUNCARG3XV(this, &val, source);
3177
    CYG_PRECONDITION_THISC();
3178
 
3179
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3180
    this->set_value(transaction, val, source);
3181
    transaction->body();
3182
    delete transaction;
3183
 
3184
    CYG_REPORT_RETURN();
3185
}
3186
 
3187
void
3188
CdlValuableBody::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
3189
{
3190
    CYG_REPORT_FUNCNAME("CdlValuable::set_enabled_and_value (no transaction)");
3191
    CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
3192
    CYG_PRECONDITION_THISC();
3193
 
3194
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3195
    this->set_enabled_and_value(transaction, enabled_arg, val, source);
3196
    transaction->body();
3197
    delete transaction;
3198
 
3199
    CYG_REPORT_RETURN();
3200
}
3201
 
3202
void
3203
CdlValuableBody::set(CdlSimpleValue& val, CdlValueSource source)
3204
{
3205
    CYG_REPORT_FUNCNAME("CdlValuable::set (no transaction)");
3206
    CYG_REPORT_FUNCARG3XV(this, &val, source);
3207
    CYG_PRECONDITION_THISC();
3208
 
3209
    CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3210
    this->set(transaction, val, source);
3211
    transaction->body();
3212
    delete transaction;
3213
 
3214
    CYG_REPORT_RETURN();
3215
}
3216
 
3217
// ----------------------------------------------------------------------------
3218
// These member functions operate in the context of a transaction. The
3219
// basic format is:
3220
//
3221
//  1) find out the state before the change
3222
//  2) make a local CdlValue copy, and modify it.
3223
//  3) update the value held in the transaction.
3224
//
3225
// Values checks etc. happen during propagation, mainly from inside
3226
// the update handler. There is code in CdlTransaction::set_whole_value()
3227
// to avoid unnecessary propagation.
3228
 
3229
void
3230
CdlValuableBody::set_source(CdlTransaction transaction, CdlValueSource source)
3231
{
3232
    CYG_REPORT_FUNCNAME("CdlValuable::set_source");
3233
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3234
    CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3235
    CYG_PRECONDITION_THISC();
3236
    CYG_PRECONDITION_CLASSC(transaction);
3237
 
3238
    const CdlValue& old_value = transaction->get_whole_value(this);
3239
    CdlValue        new_value = old_value;
3240
    new_value.set_source(source);
3241
    transaction->set_whole_value(this, old_value, new_value);
3242
 
3243
    CYG_REPORT_RETURN();
3244
}
3245
 
3246
void
3247
CdlValuableBody::invalidate_source(CdlTransaction transaction, CdlValueSource source)
3248
{
3249
    CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source");
3250
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3251
    CYG_PRECONDITION_THISC();
3252
    CYG_PRECONDITION_CLASSC(transaction);
3253
 
3254
    const CdlValue& old_value = transaction->get_whole_value(this);
3255
    CdlValue        new_value = old_value;
3256
    new_value.invalidate_source(source);
3257
    transaction->set_whole_value(this, old_value, new_value);
3258
 
3259
    CYG_REPORT_RETURN();
3260
}
3261
 
3262
void
3263
CdlValuableBody::set_enabled(CdlTransaction transaction, bool enabled_arg, CdlValueSource source)
3264
{
3265
    CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3266
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3267
    CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3268
    CYG_PRECONDITION_THISC();
3269
    CYG_PRECONDITION_CLASSC(transaction);
3270
 
3271
    const CdlValue& old_value = transaction->get_whole_value(this);
3272
    CdlValue        new_value = old_value;
3273
    new_value.set_enabled(enabled_arg, source);
3274
    transaction->set_whole_value(this, old_value, new_value);
3275
 
3276
    CYG_REPORT_RETURN();
3277
}
3278
 
3279
void
3280
CdlValuableBody::set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3281
{
3282
    CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3283
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3284
    CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3285
    CYG_PRECONDITION_THISC();
3286
    CYG_PRECONDITION_CLASSC(transaction);
3287
 
3288
    const CdlValue& old_value = transaction->get_whole_value(this);
3289
    CdlValue        new_value = old_value;
3290
    new_value.set_value(val, source);
3291
    transaction->set_whole_value(this, old_value, new_value);
3292
 
3293
    CYG_REPORT_RETURN();
3294
}
3295
 
3296
void
3297
CdlValuableBody::set_enabled_and_value(CdlTransaction transaction, bool enabled_arg, CdlSimpleValue& val,
3298
                                       CdlValueSource source)
3299
{
3300
    CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3301
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3302
    CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3303
    CYG_PRECONDITION_THISC();
3304
    CYG_PRECONDITION_CLASSC(transaction);
3305
 
3306
    const CdlValue& old_value = transaction->get_whole_value(this);
3307
    CdlValue        new_value = old_value;
3308
    new_value.set_enabled_and_value(enabled_arg, val, source);
3309
    transaction->set_whole_value(this, old_value, new_value);
3310
 
3311
    CYG_REPORT_RETURN();
3312
}
3313
 
3314
void
3315
CdlValuableBody::set(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3316
{
3317
    CYG_REPORT_FUNCNAME("CdlValuable::set");
3318
    CYG_REPORT_FUNCARG3XV(this, transaction, source);
3319
    CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3320
    CYG_PRECONDITION_THISC();
3321
    CYG_PRECONDITION_CLASSC(transaction);
3322
 
3323
    const CdlValue& old_value = transaction->get_whole_value(this);
3324
    CdlValue        new_value = old_value;
3325
    new_value.set(val, source);
3326
    transaction->set_whole_value(this, old_value, new_value);
3327
 
3328
    CYG_REPORT_RETURN();
3329
}
3330
 
3331
void
3332
CdlValuableBody::set(CdlTransaction transaction, const CdlValue& val)
3333
{
3334
    CYG_REPORT_FUNCNAME("CdlValuable::set");
3335
    CYG_REPORT_FUNCARG2XV(this, transaction);
3336
    CYG_PRECONDITION_THISC();
3337
    CYG_PRECONDITION_CLASSC(transaction);
3338
 
3339
    const CdlValue& old_value = transaction->get_whole_value(this);
3340
    CdlValue        new_value = val;
3341
    transaction->set_whole_value(this, old_value, new_value);
3342
 
3343
    CYG_REPORT_RETURN();
3344
}
3345
 
3346
//}}}
3347
//{{{  CdlValuable basics               
3348
 
3349
// ----------------------------------------------------------------------------
3350
// The CdlValuable class implements the concept of CDL objects that take
3351
// a value. There are lots of properties associated with that.
3352
 
3353
CdlValuableBody::CdlValuableBody(CdlValueFlavor flavor)
3354
    : value(flavor)
3355
{
3356
    CYG_REPORT_FUNCNAME("CdlValuable:: default constructor");
3357
    CYG_REPORT_FUNCARG1XV(this);
3358
 
3359
    cdlvaluablebody_cookie = CdlValuableBody_Magic;
3360
    CYGDBG_MEMLEAK_CONSTRUCTOR();
3361
 
3362
    CYG_POSTCONDITION_THISC();
3363
    CYG_REPORT_RETURN();
3364
}
3365
 
3366
CdlValuableBody::~CdlValuableBody()
3367
{
3368
    CYG_REPORT_FUNCNAME("CdlValuableBody:: destructor");
3369
    CYG_REPORT_FUNCARG1XV(this);
3370
    CYG_PRECONDITION_THISC();
3371
 
3372
    cdlvaluablebody_cookie = CdlValuableBody_Invalid;
3373
    CYGDBG_MEMLEAK_DESTRUCTOR();
3374
 
3375
    CYG_REPORT_RETURN();
3376
}
3377
 
3378
// ----------------------------------------------------------------------------
3379
 
3380
std::string
3381
CdlValuableBody::get_class_name() const
3382
{
3383
    CYG_REPORT_FUNCNAME("CdlValuable::get_class_name");
3384
    CYG_PRECONDITION_THISC();
3385
    CYG_REPORT_RETURN();
3386
    return "valuable";
3387
}
3388
 
3389
// ----------------------------------------------------------------------------
3390
bool
3391
CdlValuableBody::check_this(cyg_assert_class_zeal zeal) const
3392
{
3393
    if (CdlValuableBody_Magic != cdlvaluablebody_cookie) {
3394
        return false;
3395
    }
3396
    CYGDBG_MEMLEAK_CHECKTHIS();
3397
 
3398
    if (has_property(CdlPropertyId_Calculated) && (CdlValueSource_Default != value.get_source())) {
3399
        CYG_FAIL("Calculated valuables can only have a default value.");
3400
        return false;
3401
    }
3402
 
3403
    return CdlNodeBody::check_this(zeal) && value.check_this(zeal);
3404
}
3405
 
3406
//}}}
3407
//{{{  CdlValuable parsing support      
3408
 
3409
// ----------------------------------------------------------------------------
3410
// Parsing support. Adding the appropriate parsers is straightforward.
3411
 
3412
void
3413
CdlValuableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
3414
{
3415
    CYG_REPORT_FUNCNAME("CdlValuable::add_property_parsers");
3416
 
3417
    static CdlInterpreterCommandEntry commands[] =
3418
    {
3419
        CdlInterpreterCommandEntry("active_if",          &parse_active_if    ),
3420
        CdlInterpreterCommandEntry("calculated",         &parse_calculated   ),
3421
        CdlInterpreterCommandEntry("check_proc",         &parse_check_proc   ),
3422
        CdlInterpreterCommandEntry("default_value",      &parse_default_value),
3423
        CdlInterpreterCommandEntry("dialog",             &parse_dialog       ),
3424
        CdlInterpreterCommandEntry("entry_proc",         &parse_entry_proc   ),
3425
        CdlInterpreterCommandEntry("flavor",             &parse_flavor       ),
3426
        CdlInterpreterCommandEntry("group",              &parse_group        ),
3427
        CdlInterpreterCommandEntry("implements",         &parse_implements   ),
3428
        CdlInterpreterCommandEntry("legal_values",       &parse_legal_values ),
3429
        CdlInterpreterCommandEntry("requires",           &parse_requires     ),
3430
        CdlInterpreterCommandEntry("wizard",             &parse_wizard       ),
3431
        CdlInterpreterCommandEntry("",                   0                   )
3432
    };
3433
 
3434
    for (int i = 0; commands[i].command != 0; i++) {
3435
        std::vector<CdlInterpreterCommandEntry>::const_iterator j;
3436
        for (j = parsers.begin(); j != parsers.end(); j++) {
3437
            if (commands[i].name == j->name) {
3438
                if (commands[i].command != j->command) {
3439
                    CYG_FAIL("Property names are being re-used");
3440
                }
3441
                break;
3442
            }
3443
        }
3444
        if (j == parsers.end()) {
3445
            parsers.push_back(commands[i]);
3446
        }
3447
    }
3448
    CdlNodeBody::add_property_parsers(parsers);
3449
 
3450
    CYG_REPORT_RETURN();
3451
}
3452
 
3453
// Validatation is quite a bit more complicated...
3454
void
3455
CdlValuableBody::check_properties(CdlInterpreter interp)
3456
{
3457
    CYG_REPORT_FUNCNAME("CdlValuable::check_properties");
3458
    CYG_REPORT_FUNCARG2XV(this, interp);
3459
    CYG_PRECONDITION_THISC();
3460
    CYG_PRECONDITION_CLASSC(interp);
3461
 
3462
    // There should be at most one of flavor, entry_proc, check_proc,
3463
    // default_value, legal_values, dialog, and calculated. There can
3464
    // be any number of active_if, requires, and implements.
3465
    // NOTE: should multiple entry_proc's and check_proc's be allowed?
3466
    //       This could prove useful if there are a sensible number
3467
    //       of library check_proc's.
3468
    if (count_properties(CdlPropertyId_Flavor) > 1) {
3469
        CdlParse::report_error(interp, "", "There should be at most one flavor property.");
3470
    }
3471
    if (count_properties(CdlPropertyId_EntryProc) > 1) {
3472
        CdlParse::report_error(interp, "", "There should be at most one entry_proc property.");
3473
    }
3474
    if (count_properties(CdlPropertyId_CheckProc) > 1) {
3475
        CdlParse::report_error(interp, "", "There should be at most one check_proc property.");
3476
    }
3477
    if (count_properties(CdlPropertyId_DefaultValue) > 1) {
3478
        CdlParse::report_error(interp, "", "There should be at most one default_value property.");
3479
    }
3480
    if (count_properties(CdlPropertyId_LegalValues) > 1) {
3481
        CdlParse::report_error(interp, "", "There should be at most one legal_values property.");
3482
    }
3483
    if (count_properties(CdlPropertyId_Dialog) > 1) {
3484
        CdlParse::report_error(interp, "", "There should be at most one dialog property.");
3485
    }
3486
    if (count_properties(CdlPropertyId_Wizard) > 1) {
3487
        CdlParse::report_error(interp, "", "There should be at most one wizard property.");
3488
    }
3489
    if (count_properties(CdlPropertyId_Calculated) > 1) {
3490
        CdlParse::report_error(interp, "", "There should be at most one calculated property.");
3491
    }
3492
 
3493
    // If there is a flavor property, update the flavor in the base class
3494
    if (has_property(CdlPropertyId_Flavor)) {
3495
        CdlProperty_String flavor_property = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Flavor));
3496
        CYG_ASSERTC(0 != flavor_property);
3497
 
3498
        std::string flavor_string = flavor_property->get_string();
3499
        CdlValueFlavor flavor;
3500
        // The property parsing code should have caught any problems already.
3501
        if (!Cdl::string_to_flavor(flavor_string, flavor)) {
3502
            CdlParse::report_error(interp, "", "Invalid flavor " + flavor_string);
3503
        } else {
3504
            value.set_flavor(flavor);
3505
        }
3506
 
3507
        // If the flavor is "none" then the entity is not modifiable,
3508
        // and most of the properties do not make sense. However this
3509
        // is not enforced at parse-time: temporarily switching to
3510
        // flavor none may make sense during debugging.
3511
        // FIXME: no longer correct
3512
    }
3513
 
3514
    // For boolean entities legal_values does not make much sense.
3515
    // In theory a legal_values property could be used to restrict
3516
    // the value to just true or just false, but the same effect
3517
    // can be achieved more sensibly with a "requires" property.
3518
    //
3519
    // check_proc is allowed, this can be used to check programatically
3520
    // that the current value is legal.
3521
    if (CdlValueFlavor_Bool == get_flavor()) {
3522
        if (has_property(CdlPropertyId_LegalValues)) {
3523
            CdlParse::report_error(interp, "", "The \"legal_values\" property is not applicable to boolean entities.");
3524
        }
3525
    }
3526
 
3527
    // default_value and calculated are mutually exclusive
3528
    if (has_property(CdlPropertyId_Calculated) && has_property(CdlPropertyId_DefaultValue)) {
3529
        CdlParse::report_error(interp, "", "The properties \"default_value\" and \"calculated\" cannot be used together.");
3530
    }
3531
 
3532
#if 0
3533
    // Dialog is not mutually exclusive with entry_proc.
3534
    // Custom dialogs may not be supported, in which case it is likely that
3535
    // a text entry widget will be used and an entry_proc may well be
3536
    // applicable.
3537
    if (has_property(CdlPropertyId_Dialog) && has_property(CdlPropertyId_EntryProc)) {
3538
        CdlParse::report_error(interp, "", "The properties \"dialog\" and \"entry_proc\" cannot be used together.");
3539
    }
3540
#endif    
3541
 
3542
    // All of the expressions may be invalid because of unresolved references,
3543
    // ditto for implements and for dialog. 
3544
 
3545
    CdlNodeBody::check_properties(interp);
3546
 
3547
    CYG_REPORT_RETURN();
3548
}
3549
 
3550
//}}}
3551
//{{{  CdlValuable persistence support  
3552
 
3553
// ----------------------------------------------------------------------------
3554
void
3555
CdlValuableBody::initialize_savefile_support(CdlToplevel toplevel, std::string major_command)
3556
{
3557
    CYG_REPORT_FUNCNAME("CdlValuable::initialize_savefile_support");
3558
    CYG_PRECONDITION_CLASSC(toplevel);
3559
    CYG_PRECONDITIONC("" != major_command);
3560
 
3561
    toplevel->add_savefile_subcommand(major_command, "value_source", 0, &savefile_value_source_command);
3562
    toplevel->add_savefile_subcommand(major_command, "user_value",   0, &savefile_user_value_command);
3563
    toplevel->add_savefile_subcommand(major_command, "wizard_value", 0, &savefile_wizard_value_command);
3564
    toplevel->add_savefile_subcommand(major_command, "inferred_value", 0, &savefile_inferred_value_command);
3565
 
3566
    CYG_REPORT_RETURN();
3567
}
3568
 
3569
// ----------------------------------------------------------------------------
3570
// Is a savefile entry actually needed for this valuable? When performing
3571
// a minimal save there is no point in outputting valuables which have
3572
// a default value.
3573
bool
3574
CdlValuableBody::value_savefile_entry_needed() const
3575
{
3576
    CYG_REPORT_FUNCNAMETYPE("CdlValuable::value_savefile_entry_needed", "result %d");
3577
    CYG_REPORT_FUNCARG1XV(this);
3578
    CYG_PRECONDITION_THISC();
3579
 
3580
    bool result = false;
3581
 
3582
    if (this->is_modifiable()) {
3583
        if (this->has_source(CdlValueSource_User) ||
3584
            this->has_source(CdlValueSource_Wizard) ||
3585
            this->has_source(CdlValueSource_Inferred)) {
3586
 
3587
            result = true;
3588
        }
3589
    }
3590
 
3591
    CYG_REPORT_RETVAL(result);
3592
    return result;
3593
}
3594
 
3595
// ----------------------------------------------------------------------------
3596
// This utility is useful for outputting a particular value source
3597
 
3598
static std::string one    = "1";     // Needed to avoid confusing the compiler
3599
static std::string zero   = "0";
3600
 
3601
static std::string
3602
value_to_string(CdlValuable valuable, CdlValueSource source)
3603
{
3604
    CYG_REPORT_FUNCNAME("value_to_string");
3605
 
3606
    std::string data = "";
3607
 
3608
    switch(valuable->get_flavor()) {
3609
      case CdlValueFlavor_Bool :
3610
        data += (valuable->is_enabled(source) ? one : zero);
3611
        break;
3612
      case CdlValueFlavor_BoolData :
3613
        data += (valuable->is_enabled(source) ? one : zero) + " " +
3614
            CdlInterpreterBody::quote(valuable->get_value(source));
3615
        break;
3616
      case CdlValueFlavor_Data:
3617
        data += CdlInterpreterBody::quote(valuable->get_value(source));
3618
        break;
3619
      default:
3620
        CYG_FAIL("Invalid value flavor detected");
3621
        break;
3622
    }
3623
    return data;
3624
}
3625
 
3626
// Another utility to figure out the expected value source, given which
3627
// sources are available.
3628
static CdlValueSource
3629
get_expected_source(CdlValuable valuable)
3630
{
3631
    CYG_REPORT_FUNCNAMETYPE("get_expected_source", "result %d");
3632
    CYG_REPORT_FUNCARG1XV(valuable);
3633
 
3634
    CdlValueSource expected_source = CdlValueSource_Default;
3635
 
3636
    if (valuable->has_source(CdlValueSource_User)) {
3637
        expected_source = CdlValueSource_User;
3638
    } else if (valuable->has_source(CdlValueSource_Wizard)) {
3639
        expected_source = CdlValueSource_Wizard;
3640
    } else if (valuable->has_source(CdlValueSource_Inferred)) {
3641
        expected_source = CdlValueSource_Inferred;
3642
    }
3643
 
3644
    CYG_REPORT_RETVAL((int) expected_source);
3645
    return expected_source;
3646
}
3647
 
3648
// And another utility, to list the valuables listed in an expression.
3649
// e.g. for an expression of the form
3650
//
3651
//      requires (AAA + BBB) > CCC
3652
//
3653
// this would produce:
3654
//
3655
//      AAA == 1
3656
//      BBB == 2
3657
//      CCC == 0
3658
//
3659
// No indentation happens here, instead the calling code is assumed
3660
// to use multiline_comment()
3661
static std::string
3662
follow_expr_references(CdlProperty property, CdlExpression expr)
3663
{
3664
    CYG_REPORT_FUNCNAME("follow_expr_references");
3665
    CYG_REPORT_FUNCARG1XV(expr);
3666
    CYG_PRECONDITION_CLASSC(expr);
3667
 
3668
    std::string    data = "";
3669
    CdlSimpleValue simple_value;
3670
    std::vector<CdlReference>::const_iterator ref_i;
3671
 
3672
    for (ref_i = expr->references.begin(); ref_i != expr->references.end(); ref_i++) {
3673
        const std::string& refname = ref_i->get_destination_name();
3674
        CdlNode refnode = ref_i->get_destination();
3675
        CdlValuable refvaluable = 0;
3676
        if (0 != refnode) {
3677
            refvaluable = dynamic_cast<CdlValuable>(refnode);
3678
        }
3679
        data += refname + " ";
3680
        if (0 == refvaluable) {
3681
            data += "(unknown) == 0";
3682
        } else {
3683
            CdlEvalContext context(0, refvaluable, property);
3684
            CdlSimpleValue::eval_valuable(context, refvaluable, simple_value);
3685
            data += "== " + CdlInterpreterBody::quote(simple_value.get_value());
3686
        }
3687
        data += '\n';
3688
    }
3689
 
3690
    CYG_REPORT_RETURN();
3691
    return data;
3692
}
3693
 
3694
// ----------------------------------------------------------------------------
3695
 
3696
void
3697
CdlValuableBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool modifiable, bool minimal)
3698
{
3699
    CYG_REPORT_FUNCNAME("CdlValuable::save");
3700
    CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
3701
    CYG_PRECONDITION_THISC();
3702
    CYG_PRECONDITION_CLASSC(interp);
3703
 
3704
    std::string data = "";
3705
    std::string indent_string = std::string(indentation, ' ');
3706
    std::string tmp_value     = "";
3707
    CdlSimpleValue simple_value;
3708
 
3709
    // If performing a minimal save, the only fields of interest are the
3710
    // user value, the wizard value, the inferred value, and the value source.
3711
    // Not all of these need be present.
3712
    //
3713
    // Having two places where these fields get output is unfortunate,
3714
    // but the alternative is an awful lot of "if (minimal)" tests
3715
    // in the main code.
3716
    if (minimal) {
3717
 
3718
        if (modifiable) {
3719
            if (this->has_source(CdlValueSource_User)) {
3720
                data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3721
            }
3722
            if (this->has_source(CdlValueSource_Wizard)) {
3723
                data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3724
            }
3725
            if (this->has_source(CdlValueSource_Inferred)) {
3726
                data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3727
            }
3728
            CdlValueSource expected_source = get_expected_source(this);
3729
            if (expected_source != this->get_source()) {
3730
                std::string current_source_string;
3731
                if (!Cdl::source_to_string(this->get_source(), current_source_string)) {
3732
                    CYG_FAIL("Invalid current value source detected");
3733
                }
3734
                data += indent_string + "value_source " + current_source_string + "\n";
3735
            }
3736
        }
3737
 
3738
    } else {
3739
 
3740
        // Right at the start, indicate whether or not this property is active.
3741
        if (!this->is_active()) {
3742
            data += indent_string + "# This option is not active\n";
3743
            // If the entity is inactive because the parent is inactive or disabled,
3744
            // say so here. This is in addition to any unsatisfied active_if
3745
            // conditions, which will be reported below.
3746
            CdlContainer parent = this->get_parent();
3747
            if (!parent->is_active()) {
3748
                data += indent_string + "# The parent " + parent->get_name() + " is not active\n";
3749
            }
3750
            CdlValuable tmp = dynamic_cast<CdlValuable>(parent);
3751
            if ((0 != tmp) && !tmp->is_enabled()) {
3752
                data += indent_string + "# The parent " + parent->get_name() + " is disabled\n";
3753
            }
3754
        }
3755
        if (this->has_active_if_conditions()) {
3756
            std::vector<CdlProperty_GoalExpression> active_if_conditions;
3757
            this->get_active_if_conditions(active_if_conditions);
3758
            std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3759
            for (expr_i = active_if_conditions.begin(); expr_i != active_if_conditions.end(); expr_i++) {
3760
                data += indent_string + "# ActiveIf constraint: " +
3761
                    CdlInterpreterBody::extend_comment((*expr_i)->get_original_string(), indentation, 4) +
3762
                    '\n';
3763
 
3764
                CdlExpression expr = (*expr_i)->get_expression();
3765
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3766
                CdlEvalContext context(0, this, *expr_i);
3767
                bool active_if_value = false;
3768
                try {
3769
                    active_if_value = (*expr_i)->eval(context);
3770
                } catch(CdlEvalException e) {
3771
                    active_if_value = false;
3772
                } catch(std::bad_alloc) {
3773
                    throw;
3774
                }
3775
                data += indent_string + "#   --> " + (active_if_value ? one : zero) + "\n";
3776
            }
3777
        }
3778
 
3779
        // If there has been any information related to the active status,
3780
        // add a blank line before we start worrying about values.
3781
        if (0 < data.size()) {
3782
            data += '\n';
3783
        }
3784
 
3785
        if (CdlValueFlavor_None == this->get_flavor()) {
3786
            data += indent_string + "# There is no associated value.\n";
3787
        } else if (this->has_property(CdlPropertyId_Calculated)) {
3788
            CdlProperty_Expression expr = this->get_calculated_expression();
3789
            data += indent_string + "# Calculated value: " +
3790
                CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + '\n';
3791
            data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3792
        } else if (!modifiable) {
3793
            data += indent_string + "# This value cannot be modified here.\n";
3794
        }
3795
 
3796
        // Output the flavor. This clutters up the savefile a bit.
3797
        // However it is necessary so that the user can distinguish
3798
        // between bool, booldata and data items
3799
        switch(this->get_flavor()) {
3800
          case CdlValueFlavor_Bool:
3801
            data += indent_string + "# Flavor: bool\n";
3802
            break;
3803
          case CdlValueFlavor_BoolData:
3804
            data += indent_string + "# Flavor: booldata\n";
3805
            break;
3806
          case CdlValueFlavor_Data:
3807
            data += indent_string + "# Flavor: data\n";
3808
            break;
3809
          default:
3810
            break;
3811
        }
3812
 
3813
        // If the value is not modifiable, just list the current value.
3814
        // This is not in a form that allows users to change it easily.
3815
        if (!modifiable) {
3816
            switch(this->get_flavor()) {
3817
              case CdlValueFlavor_None :
3818
                break;
3819
              case CdlValueFlavor_Bool :
3820
                data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + '\n';
3821
                break;
3822
              case CdlValueFlavor_BoolData :
3823
                data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + " " +
3824
                    CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3825
                break;
3826
              case CdlValueFlavor_Data :
3827
                data += indent_string + "# Current_value: " +
3828
                    CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3829
                break;
3830
              default:
3831
                break;
3832
            }
3833
 
3834
        } else if (CdlValueFlavor_None != this->get_flavor()) {
3835
 
3836
            // If there is a user value, output it. Otherwise output
3837
            // a comment that allows users to edit the user value conveniently.
3838
            // It is assumed that the user will want a value similar to the
3839
            // default one, so that is provided as the starting point
3840
            if (this->has_source(CdlValueSource_User)) {
3841
                data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3842
            } else {
3843
                data += indent_string + "# No user value, uncomment the following line to provide one.\n" +
3844
                    indent_string + "# user_value " +
3845
                    CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 0) + "\n";
3846
            }
3847
 
3848
            // Output a wizard value iff there is one. There is little point
3849
            // in letting users edit a wizard value, they should be running
3850
            // the wizard itself.
3851
            if (this->has_source(CdlValueSource_Wizard)) {
3852
                data += indent_string + "# The wizard value should not be edited directly.\n" +
3853
                    indent_string + "# Instead the wizard should be run again if necessary.\n";
3854
                data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3855
            }
3856
 
3857
            // List the inferred value. This needs to be a command,
3858
            if (this->has_source(CdlValueSource_Inferred)) {
3859
                data += indent_string + "# The inferred value should not be edited directly.\n";
3860
                data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3861
            }
3862
 
3863
            // Output the value source iff it is unusual. If the current
3864
            // source is the highest priority one then there is no point
3865
            // in outputting a command, but a comment is usual. The value
3866
            // source needs to come after wizard and inferred values
3867
            std::string    current_source_string;
3868
            CdlValueSource expected_source = get_expected_source(this);
3869
            CdlValueSource current_source  = this->get_source();
3870
            if (!Cdl::source_to_string(current_source, current_source_string)) {
3871
                CYG_FAIL("Invalid current value source detected");
3872
            }
3873
            if (this->get_source() == expected_source) {
3874
                data += indent_string + "# value_source " + current_source_string + "\n";
3875
            } else {
3876
                data += indent_string + "value_source " + current_source_string + "\n";
3877
            }
3878
 
3879
            // Always output the default value as a comment.
3880
            data += indent_string + "# Default value: ";
3881
 
3882
            // If there is no default_value expression or if the expression involves
3883
            // only constants, just output the current default value. Otherwise
3884
            // output both the expression and the value
3885
            CdlProperty prop = this->get_property(CdlPropertyId_DefaultValue);
3886
            CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
3887
            if ((0 == expr) || (0 == expr->references.size())) {
3888
                // There is no default_value expression, so just output the current value
3889
                data += CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4)
3890
                    + "\n";
3891
            } else {
3892
                data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + "\n";
3893
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3894
                data += indent_string + "#   --> " +
3895
                    CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4) + "\n";
3896
            }
3897
        }
3898
 
3899
        // If there is a legal_values property, add the details.
3900
        if (this->has_property(CdlPropertyId_LegalValues)) {
3901
            CdlProperty_ListExpression lexpr = this->get_legal_values();
3902
            data += indent_string + "# Legal values: " +
3903
                CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4) + '\n';
3904
 
3905
            std::vector<CdlExpression>::const_iterator expr_i;
3906
            std::vector<std::pair<CdlExpression,CdlExpression> >::const_iterator ranges_i;
3907
            for (expr_i = lexpr->data.begin(); expr_i != lexpr->data.end(); expr_i++) {
3908
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, *expr_i), indentation, 4);
3909
            }
3910
            for (ranges_i = lexpr->ranges.begin(); ranges_i != lexpr->ranges.end(); ranges_i++) {
3911
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->first), indentation, 4);
3912
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->second), indentation, 4);
3913
            }
3914
        }
3915
 
3916
        // If there is a check_proc property, mention this.
3917
        if (this->has_property(CdlPropertyId_CheckProc)) {
3918
            data += indent_string + "# There is a check_proc routine that will check the value.\n";
3919
        }
3920
 
3921
        // Output all requires properties
3922
        if (this->has_property(CdlPropertyId_Requires)) {
3923
            std::vector<CdlProperty_GoalExpression> requires_goals;
3924
            this->get_requires_goals(requires_goals);
3925
            std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3926
            for (expr_i = requires_goals.begin(); expr_i != requires_goals.end(); expr_i++) {
3927
                data += indent_string + "# Requires: " +
3928
                    CdlInterpreterBody::extend_comment((*expr_i)->get_original_string(), indentation, 4) + "\n";
3929
 
3930
                CdlExpression expr = (*expr_i)->get_expression();
3931
                data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3932
                CdlEvalContext context(0, this, *expr_i);
3933
                bool active_if_value = false;
3934
                try {
3935
                    active_if_value = (*expr_i)->eval(context);
3936
                } catch(CdlEvalException e) {
3937
                    active_if_value = false;
3938
                } catch(std::bad_alloc) {
3939
                    throw;
3940
                }
3941
                data += indent_string + "#   --> " + (active_if_value ? one : zero) + "\n";
3942
            }
3943
        }
3944
 
3945
        // Output all dependencies that other entities may have on this one.
3946
        const std::vector<CdlReferrer>& referrers = this->get_referrers();
3947
        if (0 != referrers.size()) {
3948
            data += '\n' + indent_string + "# The following properties are affected by this value\n";
3949
            std::vector<CdlReferrer>::const_iterator ref_i;
3950
            for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
3951
 
3952
                CdlNode source = ref_i->get_source();
3953
                CdlProperty source_prop = ref_i->get_source_property();
3954
                std::string prop_id = source_prop->get_property_name();
3955
 
3956
                if ((prop_id == CdlPropertyId_ActiveIf)     ||
3957
                    (prop_id == CdlPropertyId_Calculated)   ||
3958
                    (prop_id == CdlPropertyId_DefaultValue) ||
3959
                    (prop_id == CdlPropertyId_LegalValues)  ||
3960
                    (prop_id == CdlPropertyId_Requires)) {
3961
 
3962
                    data += indent_string + "# " + source->get_class_name() + " " + source->get_name() + "\n";
3963
                    data += indent_string + "#     " + prop_id + ": ";
3964
                    if ((prop_id == CdlPropertyId_Calculated) || (prop_id == CdlPropertyId_DefaultValue)) {
3965
                        CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(source_prop);
3966
                        CYG_ASSERT_CLASSC(expr);
3967
                        data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4);
3968
                    } else if (prop_id == CdlPropertyId_LegalValues) {
3969
                        CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(source_prop);
3970
                        CYG_ASSERT_CLASSC(lexpr);
3971
                        data += CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4);
3972
                    } else if ((prop_id == CdlPropertyId_ActiveIf) || (prop_id == CdlPropertyId_Requires)) {
3973
                        CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(source_prop);
3974
                        CYG_ASSERT_CLASSC(gexpr);
3975
                        data += CdlInterpreterBody::extend_comment(gexpr->get_original_string(), indentation, 4);
3976
                    }
3977
                    data += '\n';
3978
                }
3979
            }
3980
        }
3981
    }
3982
 
3983
    interp->write_data(chan, data);
3984
 
3985
    CYG_REPORT_RETURN();
3986
}
3987
 
3988
int
3989
CdlValuableBody::savefile_value_source_command(CdlInterpreter interp, int argc, const char* argv[])
3990
{
3991
    CYG_REPORT_FUNCNAME("CdlValuable::savefile_value_source_command");
3992
    CYG_REPORT_FUNCARG2XV(interp, argc);
3993
    CYG_PRECONDITION_CLASSC(interp);
3994
 
3995
    CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
3996
    CYG_ASSERT_CLASSC(valuable);
3997
    CdlTransaction transaction = interp->get_transaction();
3998
    CYG_ASSERT_CLASSC(transaction);
3999
 
4000
    CdlValueSource source = CdlValueSource_Invalid;
4001
    if ((2 != argc) || !Cdl::string_to_source(argv[1], source) || !valuable->has_source(transaction, source)) {
4002
        std::string msg = "Invalid value_source command for ";
4003
        msg += valuable->get_class_name() + " " + valuable->get_name() + "\n";
4004
        if (CdlValueSource_Invalid == source) {
4005
            msg += "Expecting one argument, which should \"user\", \"wizard\", \"inferred\" or \"default\"";
4006
        } else {
4007
            msg += "The specified value source is not valid.";
4008
        }
4009
        CdlParse::report_error(interp, "", msg);
4010
    } else {
4011
        valuable->set_source(transaction, source);
4012
    }
4013
 
4014
    return TCL_OK;
4015
}
4016
 
4017
int
4018
CdlValuableBody::savefile_xxx_value_command(CdlInterpreter interp, int argc, const char* argv[], CdlValueSource source)
4019
{
4020
    CYG_REPORT_FUNCNAME("CdlValuable::savefile_xxx_value_command");
4021
    CYG_REPORT_FUNCARG3XV(interp, argc, source);
4022
    CYG_PRECONDITION_CLASSC(interp);
4023
 
4024
    CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
4025
    CYG_ASSERT_CLASSC(valuable);
4026
    CdlTransaction transact = interp->get_transaction();
4027
    CYG_ASSERT_CLASSC(transact);
4028
 
4029
    bool error = false;
4030
    bool warn  = false;
4031
    std::string msg = "";
4032
    if (CdlValueFlavor_None == valuable->get_flavor()) {
4033
        msg = "Options with flavor \"none\" cannot be modified.";
4034
        error = true;
4035
    } else if (!valuable->is_modifiable()) {
4036
        msg = "This option is not user-modifiable.";
4037
        error = true;
4038
    } else {
4039
        switch(valuable->get_flavor()) {
4040
          case CdlValueFlavor_Bool :
4041
              if (2 != argc) {
4042
                  msg = "Invalid boolean value, expecting 0 or 1";
4043
                  error = true;
4044
              } else {
4045
                  bool x;
4046
                  Cdl::string_to_bool(argv[1], x);
4047
                  valuable->set_enabled(transact, x, source);
4048
              }
4049
              break;
4050
          case CdlValueFlavor_Data :
4051
              if (2 != argc) {
4052
                  msg = "Invalid data value, expecting a single string";
4053
                  error = true;
4054
              } else {
4055
                  valuable->set_value(transact, argv[1], source);
4056
              }
4057
              break;
4058
          case CdlValueFlavor_BoolData:
4059
              if (3 != argc) {
4060
                  msg = "Invalid booldata value, expecting a boolean followed by a string";
4061
                  error = true;
4062
              } else {
4063
                  bool x;
4064
                  Cdl::string_to_bool(argv[1], x);
4065
                  valuable->set_enabled_and_value(transact, x, argv[2], source);
4066
              }
4067
              break;
4068
          default:
4069
            CYG_FAIL("Invalid value flavor detected");
4070
            break;
4071
        }
4072
    }
4073
 
4074
    if (error || warn) {
4075
        msg = std::string("Invalid value command for ") + valuable->get_class_name() + " " + valuable->get_name() + "\n"
4076
            + msg;
4077
        if (error) {
4078
            CdlParse::report_error(interp, "", msg);
4079
        } else {
4080
            CdlParse::report_warning(interp, "", msg);
4081
        }
4082
    }
4083
 
4084
    return TCL_OK;
4085
}
4086
 
4087
int
4088
CdlValuableBody::savefile_user_value_command(CdlInterpreter interp, int argc, const char* argv[])
4089
{
4090
    CYG_REPORT_FUNCNAME("CdlValuable::savefile_user_value_command");
4091
    int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_User);
4092
    CYG_REPORT_RETURN();
4093
    return result;
4094
}
4095
 
4096
int
4097
CdlValuableBody::savefile_wizard_value_command(CdlInterpreter interp, int argc, const char* argv[])
4098
{
4099
    CYG_REPORT_FUNCNAME("CdlValuable::savefile_wizard_value_command");
4100
    int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Wizard);
4101
    CYG_REPORT_RETURN();
4102
    return result;
4103
}
4104
 
4105
int
4106
CdlValuableBody::savefile_inferred_value_command(CdlInterpreter interp, int argc, const char* argv[])
4107
{
4108
    CYG_REPORT_FUNCNAME("CdlValuable::savefile_inferred_value_command");
4109
    int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Inferred);
4110
    CYG_REPORT_RETURN();
4111
    return result;
4112
}
4113
 
4114
//}}}

powered by: WebSVN 2.1.0

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