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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [host/] [libcdl/] [value.cxx] - Blame information for rev 816

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

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

powered by: WebSVN 2.1.0

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