]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - tools/src/libcdl/func.cxx
Initial revision
[karo-tx-redboot.git] / tools / src / libcdl / func.cxx
1 //{{{  Banner                           
2
3 //============================================================================
4 //
5 //      func.cxx
6 //
7 //      Implementation of CDL functions
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //                                                                          
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 2001 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
17 // This program is free software; you can redistribute it and/or modify it 
18 // under the terms of the GNU General Public License as published by the Free 
19 // Software Foundation; either version 2 of the License, or (at your option) 
20 // any later version.
21 // 
22 // This program is distributed in the hope that it will be useful, but WITHOUT 
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
24 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for 
25 // more details.
26 // 
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc., 
29 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
30 //
31 // ----------------------------------------------------------------------------
32 //                                                                          
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s):   bartv
38 // Contact(s):  bartv
39 // Date:        2001/04/20
40 // Version:     0.01
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{  #include's                       
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
60
61 //}}}
62
63 //{{{  Core                             
64
65 // ----------------------------------------------------------------------------
66 int CdlFunction::next_id        = 1;
67 std::vector<CdlFunction*>       CdlFunction::all_functions;
68
69 // Dummy initializers, for e.g. when a particular function implementation does not
70 // support a certain type of inference.
71 void (*CdlFunction::null_check)(CdlExpression, const CdlSubexpression&) =
72      (void (*)(CdlExpression, const CdlSubexpression&)) 0;
73 bool (*CdlFunction::null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int) =
74      (bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int)) 0;
75 bool (*CdlFunction::null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int) =
76      (bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)) 0;
77
78
79 CdlFunction::CdlFunction(const char* name_arg, int number_args_arg,
80                          void (*check_arg)(CdlExpression, const CdlSubexpression&),
81                          void (*eval_arg)(CdlEvalContext&, CdlExpression, const CdlSubexpression&, CdlSimpleValue&),
82                          bool (*infer_bool_arg)(CdlTransaction, CdlExpression, unsigned int, bool, int),
83                          bool (*infer_value_arg)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int))
84     : name(name_arg),
85       number_args(number_args_arg),
86       check_fn(check_arg),
87       eval_fn(eval_arg),
88       infer_bool_fn(infer_bool_arg),
89       infer_value_fn(infer_value_arg)
90 {
91     id  = next_id++;
92     all_functions.push_back(this);
93 }
94
95 CdlFunction::~CdlFunction()
96 {
97 }
98
99 bool
100 CdlFunction::is_function(std::string name, int& id)
101 {
102     CYG_REPORT_FUNCNAMETYPE("CdlFunction::is_function", "result %d");
103     
104     bool result = false;
105     std::vector<CdlFunction*>::const_iterator i;
106     
107     for (i = all_functions.begin(); !result && (i != all_functions.end()); i++) {
108         if (name == (*i)->name) {
109             result = true;
110             id = (*i)->id;
111         }
112     }
113
114     CYG_REPORT_RETVAL(result);
115     return result;
116 }
117
118 std::string
119 CdlFunction::get_name(int id)
120 {
121     CYG_REPORT_FUNCNAME("CdlFunction::get_name");
122     CYG_REPORT_FUNCARG1XV(id);
123     
124     std::string result  = "";
125     std::vector<CdlFunction*>::const_iterator i;
126     
127     for (i = all_functions.begin(); i != all_functions.end(); i++) {
128         if (id == (*i)->id) {
129             result = (*i)->name;
130             break;
131         }
132     }
133
134     CYG_REPORT_RETURN();
135     return result;
136 }
137
138 int
139 CdlFunction::get_args_count(int id)
140 {
141     CYG_REPORT_FUNCNAMETYPE("CdlFunction::get_args_count", "result %d");
142     CYG_REPORT_FUNCARG1XV(id);
143     
144     int result = 0;
145     std::vector<CdlFunction*>::const_iterator i;
146     
147     for (i = all_functions.begin(); i != all_functions.end(); i++) {
148         if (id == (*i)->id) {
149             result = (*i)->number_args;;
150             break;
151         }
152     }
153     CYG_REPORT_RETVAL(result);
154     return result;
155 }
156
157 void
158 CdlFunction::check(CdlExpression expr, const CdlSubexpression& subexpr)
159 {
160     CYG_REPORT_FUNCNAME("CdlFunction::check");
161     CYG_REPORT_FUNCARG2XV(expr, &subexpr);
162     
163     int id = subexpr.func;
164     std::vector<CdlFunction*>::const_iterator i;
165     
166     for (i = all_functions.begin(); i != all_functions.end(); i++) {
167         if (id == (*i)->id) {
168             if (CdlFunction::null_check != (*i)->check_fn) {
169                 (*((*i)->check_fn))(expr, subexpr);
170             }
171             break;
172         }
173     }
174
175     CYG_REPORT_RETURN();
176 }
177
178 void
179 CdlFunction::eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
180 {
181     CYG_REPORT_FUNCNAME("CdlFunction::eval");
182     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
183     
184     int id = subexpr.func;
185     std::vector<CdlFunction*>::const_iterator i;
186     
187     for (i = all_functions.begin(); i != all_functions.end(); i++) {
188         if (id == (*i)->id) {
189             (*((*i)->eval_fn))(context, expr, subexpr, result);
190             break;
191         }
192     }
193
194     CYG_REPORT_RETURN();
195 }
196
197 bool
198 CdlFunction::infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
199 {
200     CYG_REPORT_FUNCNAMETYPE("CdlFunction::infer_bool", "result %d");
201     CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
202
203     bool result = false;
204     CdlSubexpression& subexpr = expr->sub_expressions[index];
205     int id = subexpr.func;
206     std::vector<CdlFunction*>::const_iterator i;
207
208     for (i = all_functions.begin(); i != all_functions.end(); i++) {
209         if (id == (*i)->id) {
210             if (CdlFunction::null_infer_bool != (*i)->infer_bool_fn) {
211                 result = (*((*i)->infer_bool_fn))(transaction, expr, index, goal, level);
212             }
213             break;
214         }
215     }
216
217     CYG_REPORT_RETVAL(result);
218     return result;
219 }
220
221 bool
222 CdlFunction::infer_value(CdlTransaction transaction, CdlExpression expr, unsigned int index, CdlSimpleValue& goal, int level)
223 {
224     CYG_REPORT_FUNCNAMETYPE("CdlFunction::infer_value", "result %d");
225     CYG_REPORT_FUNCARG5XV(transaction, expr, index, &goal, level);
226     
227     bool result = false;
228     CdlSubexpression& subexpr = expr->sub_expressions[index];
229     int id = subexpr.func;
230     std::vector<CdlFunction*>::const_iterator i;
231
232     for (i = all_functions.begin(); i != all_functions.end(); i++) {
233         if (id == (*i)->id) {
234             if (CdlFunction::null_infer_value != (*i)->infer_value_fn) {
235                 result = (*((*i)->infer_value_fn))(transaction, expr, index, goal, level);
236             }
237             break;
238         }
239     }
240
241     CYG_REPORT_RETVAL(result);
242     return result;
243 }
244
245 //}}}
246 //{{{  is_substr()                      
247
248 // ----------------------------------------------------------------------------
249 // is_substr(A, B)
250 //
251 // For example, is_substr(CYGBLD_GLOBAL_CFLAGS, " -fno-exceptions ")
252 //
253 // There is one subtlety about substring matching: what to do about the
254 // start and end of a string. If the specified substring begins with a
255 // space then this will match either a space or the start of the string,
256 // similarly for the final character.
257
258 static std::string::size_type
259 is_substr_find(std::string haystack, std::string needle, std::string::size_type& len_arg)
260 {
261     CYG_REPORT_FUNCNAMETYPE("is_substr_find", "result %d");
262     std::string::size_type result       = std::string::npos;
263
264     std::string::size_type haystack_len = haystack.length();
265     std::string::size_type needle_len   = needle.length();
266
267     bool leading_space = false;
268     bool trailing_space = false;
269     
270     if (' ' == needle[0]) {
271         leading_space = true;
272         needle_len--;
273         needle = std::string(needle, 1, needle_len);
274     }
275     if (' ' == needle[needle_len - 1]) {
276         trailing_space = true;
277         needle_len--;
278         needle = std::string(needle, 0, needle_len);
279     }
280
281     std::string::size_type posn = haystack.find(needle);
282     while ((std::string::npos == result) && (std::string::npos != posn)) {
283
284         std::string::size_type match_point = posn;
285         bool match = true;
286
287         // A possible match has been found. If there was a leading
288         // space, check we are either at the start of the main string
289         // or that a space is present.
290         if (leading_space && (0 != posn) && (' ' != haystack[posn - 1])) {
291             match = false;
292         }
293         if (trailing_space && (haystack_len != (posn + needle_len)) && (' ' != haystack[posn + needle_len])) {
294             match = false;
295         }
296
297         // The result and len_arg returns exclude the spaces. This is deliberate.
298         // Consider !is_substr("-g -O2 -fno-rtti -fno-exceptions", " -fnortti ").
299         // If during inference the spaces were removed as well, this would give
300         // "-g -O2-fno-exceptions", which is not desirable.
301         if (match) {
302             result  = match_point;
303             len_arg = needle_len;
304         } else {
305             posn = haystack.find(needle, posn + 1);
306         }
307     }
308
309     CYG_REPORT_RETVAL(result);
310     return result;
311 }
312
313 static void
314 is_substr_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
315 {
316     CYG_REPORT_FUNCNAME("is_substr_eval");
317     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
318     CYG_PRECONDITION_CLASSOC(context);
319     CYG_PRECONDITION_CLASSC(expr);
320
321     CdlSimpleValue      arg0;
322     CdlSimpleValue      arg1;
323     expr->eval_subexpression(context, subexpr.args[0], arg0);
324     expr->eval_subexpression(context, subexpr.args[1], arg1);
325
326     std::string::size_type len;
327     result = (std::string::npos != is_substr_find(arg0.get_value(), arg1.get_value(), len));
328     CYG_REPORT_RETURN();
329 }
330
331 // Inference is only supported if the haystack argument is a reference that can be
332 // updated. The needle can be an arbitrary expression.
333 static bool
334 is_substr_infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
335 {
336     CYG_REPORT_FUNCNAMETYPE("is_substr_infer_bool", "result %d");
337     CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
338
339     bool result = false;
340
341     CdlSubexpression& subexpr   = expr->sub_expressions[index];
342     CdlSubexpression& arg0      = expr->sub_expressions[subexpr.args[0]];
343     try {
344         if (CdlExprOp_Reference == arg0.op) {
345
346             CdlSimpleValue  needle_value;
347             CdlEvalContext context(transaction);
348             expr->eval_subexpression(context, subexpr.args[1], needle_value);
349             std::string     needle  = needle_value.get_value();
350
351             CdlNode         node        = expr->references[arg0.reference_index].get_destination();
352             CdlValuable     valuable    = 0;
353             if (0 != node) {
354                 valuable = dynamic_cast<CdlValuable>(node);
355             }
356             if ((0 != valuable) && ((CdlValueFlavor_BoolData == valuable->get_flavor()) ||
357                                     (CdlValueFlavor_Data == valuable->get_flavor()))) {
358                 // OK, we have a valuable which can be given a suitable value.
359                 // What is the current string?
360                 const CdlValue& current_value   = transaction->get_whole_value(valuable);
361                 std::string haystack            = current_value.get_simple_value().get_value();
362
363                 // What is the goal? If the needle should be in the
364                 // haystack, append it if necessary. If the needle
365                 // should not be in the haystack, remove all current occurrences.
366                 if (goal) {
367                     std::string::size_type len;
368                     if (std::string::npos == is_substr_find(haystack, needle, len)) {
369                         haystack = haystack + needle;
370                     }
371                 } else {
372                     std::string::size_type posn, len;
373                     for (posn = is_substr_find(haystack, needle, len);
374                          std::string::npos != posn;
375                          posn = is_substr_find(haystack, needle, len)) {
376                         haystack.erase(posn, len);
377                     }
378                 }
379
380                 // OK, we have a new value for the haystack which should match the desired goal.
381                 // Try and set this value.
382                 CdlSimpleValue  new_value(haystack);
383                 result = CdlInfer::set_valuable_value(transaction, valuable, new_value, level);
384             }
385         }
386     } catch (...) {
387         result = false;
388     }
389     
390     CYG_REPORT_RETVAL(result);
391     return result;
392 }
393
394 static CdlFunction is_substr("is_substr", 2, CdlFunction::null_check, &is_substr_eval,
395                              &is_substr_infer_bool, CdlFunction::null_infer_value);
396
397 //}}}
398 //{{{  is_xsubstr()                     
399
400 // ----------------------------------------------------------------------------
401 // is_xsubstr(A, B)
402 //
403 // Like is_substr() but only deals with exact matches, i.e. there is no special
404 // treatment for leading and trailing spaces in the needle.
405
406 static void
407 is_xsubstr_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
408 {
409     CYG_REPORT_FUNCNAME("is_xsubstr_eval");
410     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
411     CYG_PRECONDITION_CLASSOC(context);
412     CYG_PRECONDITION_CLASSC(expr);
413
414     CdlSimpleValue      arg0;
415     CdlSimpleValue      arg1;
416     expr->eval_subexpression(context, subexpr.args[0], arg0);
417     expr->eval_subexpression(context, subexpr.args[1], arg1);
418
419     result = (std::string::npos != arg0.get_value().find(arg1.get_value()));
420     CYG_REPORT_RETURN();
421 }
422
423 // Inference is only supported if the haystack argument is a reference that can be
424 // updated. The needle can be an arbitrary expression.
425 static bool
426 is_xsubstr_infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
427 {
428     CYG_REPORT_FUNCNAMETYPE("is_xsubstr_infer_bool", "result %d");
429     CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
430
431     bool result = false;
432
433     CdlSubexpression& subexpr   = expr->sub_expressions[index];
434     CdlSubexpression& arg0      = expr->sub_expressions[subexpr.args[0]];
435     try {
436         if (CdlExprOp_Reference == arg0.op) {
437
438             CdlSimpleValue  needle_value;
439             CdlEvalContext context(transaction);
440             expr->eval_subexpression(context, subexpr.args[1], needle_value);
441             std::string     needle  = needle_value.get_value();
442
443             CdlNode         node        = expr->references[arg0.reference_index].get_destination();
444             CdlValuable     valuable    = 0;
445             if (0 != node) {
446                 valuable = dynamic_cast<CdlValuable>(node);
447             }
448             if ((0 != valuable) && ((CdlValueFlavor_BoolData == valuable->get_flavor()) ||
449                                     (CdlValueFlavor_Data == valuable->get_flavor()))) {
450                 // OK, we have a valuable which can be given a suitable value.
451                 // What is the current string?
452                 const CdlValue& current_value   = transaction->get_whole_value(valuable);
453                 std::string haystack            = current_value.get_simple_value().get_value();
454
455                 // What is the goal? If the needle should be in the
456                 // haystack, append it if necessary. If the needle
457                 // should not be in the haystack, remove all current occurrences.
458                 if (goal) {
459                     if (std::string::npos == haystack.find(needle)) {
460                         haystack = haystack + needle;
461                     }
462                 } else {
463                     std::string::size_type posn;
464                     for (posn = haystack.find(needle); std::string::npos != posn; posn = haystack.find(needle)) {
465                         haystack.erase(posn, needle.length());
466                     }
467                 }
468
469                 // OK, we have a new value for the haystack which should match the desired goal.
470                 // Try and set this value.
471                 CdlSimpleValue  new_value(haystack);
472                 result = CdlInfer::set_valuable_value(transaction, valuable, new_value, level);
473             }
474         }
475     } catch (...) {
476         result = false;
477     }
478     
479     CYG_REPORT_RETVAL(result);
480     return result;
481 }
482
483 static CdlFunction is_xsubstr("is_xsubstr", 2, CdlFunction::null_check, &is_xsubstr_eval,
484                               &is_xsubstr_infer_bool, CdlFunction::null_infer_value);
485
486 //}}}
487 //{{{  is_loaded()                      
488
489 // ----------------------------------------------------------------------------
490 // is_loaded(x)
491 // Check whether or not a particular configuration option is loaded.
492 // This takes a single argument which must be a reference. No
493 // inference is possible, since loading and unloading packages is
494 // currently beyond the scope of the inference engine.
495
496 static void
497 is_loaded_check(CdlExpression expr, const CdlSubexpression& subexpr)
498 {
499     CYG_REPORT_FUNCNAME("is_loaded_check");
500     CYG_REPORT_FUNCARG2XV(expr, &subexpr);
501
502     CdlSubexpression& arg0 = expr->sub_expressions[subexpr.args[0]];
503     if (CdlExprOp_Reference != arg0.op) {
504         throw CdlParseException(std::string("The argument to is_loaded() should be a reference to a configuration option.\n") +
505                                 CdlParse::get_expression_error_location());
506     }
507     
508     CYG_REPORT_RETURN();
509 }
510
511 static void
512 is_loaded_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
513 {
514     CYG_REPORT_FUNCNAME("is_loaded_eval");
515     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
516     CYG_PRECONDITION_CLASSOC(context);
517     CYG_PRECONDITION_CLASSC(expr);
518
519     CdlSubexpression arg0 = expr->sub_expressions[subexpr.args[0]];
520     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
521
522     result = (0 != context.resolve_reference(expr, arg0.reference_index));
523     CYG_REPORT_RETURN();
524 }
525
526 static CdlFunction is_loaded("is_loaded", 1, &is_loaded_check, &is_loaded_eval,
527                              CdlFunction::null_infer_bool, CdlFunction::null_infer_value);
528
529 //}}}
530 //{{{  is_active()                      
531
532 // ----------------------------------------------------------------------------
533 // is_active(x)
534 // Check whether or not a particular configuration option is loaded
535 // and active. This takes a single argument which must be a reference.
536
537 static void
538 is_active_check(CdlExpression expr, const CdlSubexpression& subexpr)
539 {
540     CYG_REPORT_FUNCNAME("is_active_check");
541     CYG_REPORT_FUNCARG2XV(expr, &subexpr);
542
543     CdlSubexpression& arg0 = expr->sub_expressions[subexpr.args[0]];
544     if (CdlExprOp_Reference != arg0.op) {
545         throw CdlParseException(std::string("The argument to is_active() should be a reference to a configuration option.\n") +
546                                 CdlParse::get_expression_error_location());
547     }
548     
549     CYG_REPORT_RETURN();
550 }
551
552 static void
553 is_active_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
554 {
555     CYG_REPORT_FUNCNAME("is_active_eval");
556     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
557     CYG_PRECONDITION_CLASSOC(context);
558     CYG_PRECONDITION_CLASSC(expr);
559
560     CdlSubexpression arg0 = expr->sub_expressions[subexpr.args[0]];
561     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
562
563     CdlNode node = context.resolve_reference(expr, arg0.reference_index);
564     if (0 != node) {
565         result = node->is_active(context.transaction);
566     } else {
567         result = false;
568     }
569     CYG_REPORT_RETURN();
570 }
571
572 static bool
573 is_active_infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
574 {
575     CYG_REPORT_FUNCNAMETYPE("is_active_infer_bool", "result %d");
576     CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
577
578     bool result = false;
579
580     CdlSubexpression subexpr    = expr->sub_expressions[index];
581     CdlSubexpression arg0       = expr->sub_expressions[subexpr.args[0]];
582     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
583
584     CdlNode node = expr->references[arg0.reference_index].get_destination();
585     if (0 != node) {
586         if (goal) {
587             result = CdlInfer::make_active(transaction, node, level);
588         } else {
589             result = CdlInfer::make_inactive(transaction, node, level);
590         }
591     }
592     
593     CYG_REPORT_RETVAL(result);
594     return result;
595 }
596
597 static CdlFunction is_active("is_active", 1, &is_active_check, &is_active_eval,
598                              &is_active_infer_bool, CdlFunction::null_infer_value);
599
600 //}}}
601 //{{{  is_enabled()                     
602
603 // ----------------------------------------------------------------------------
604 // is_enabled(x)
605 // Check whether or not a particular configuration option is loaded
606 // and enabled. The active/inactive state is ignored. This function
607 // takes a single argument which must be a reference.
608
609 static void
610 is_enabled_check(CdlExpression expr, const CdlSubexpression& subexpr)
611 {
612     CYG_REPORT_FUNCNAME("is_enabled_check");
613     CYG_REPORT_FUNCARG2XV(expr, &subexpr);
614
615     CdlSubexpression& arg0 = expr->sub_expressions[subexpr.args[0]];
616     if (CdlExprOp_Reference != arg0.op) {
617         throw CdlParseException(std::string("The argument to is_enabled() should be a reference to a configuration option.\n") +
618                                 CdlParse::get_expression_error_location());
619     }
620     
621     CYG_REPORT_RETURN();
622 }
623
624 static void
625 is_enabled_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
626 {
627     CYG_REPORT_FUNCNAME("is_enabled_eval");
628     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
629     CYG_PRECONDITION_CLASSOC(context);
630     CYG_PRECONDITION_CLASSC(expr);
631
632     CdlSubexpression arg0 = expr->sub_expressions[subexpr.args[0]];
633     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
634
635     CdlValuable valuable = context.resolve_valuable_reference(expr, arg0.reference_index);
636     if (0 != valuable) {
637         if (0 != context.transaction) {
638             result = valuable->is_enabled(context.transaction);
639         } else {
640             result = valuable->is_enabled();
641         }
642     } else {
643         result = false;
644     }
645     CYG_REPORT_RETURN();
646 }
647
648 static bool
649 is_enabled_infer_bool(CdlTransaction transaction, CdlExpression expr, unsigned int index, bool goal, int level)
650 {
651     CYG_REPORT_FUNCNAMETYPE("is_enabled_infer_bool", "result %d");
652     CYG_REPORT_FUNCARG5XV(transaction, expr, index, goal, level);
653
654     bool result = false;
655
656     CdlSubexpression subexpr    = expr->sub_expressions[index];
657     CdlSubexpression arg0       = expr->sub_expressions[subexpr.args[0]];
658     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
659
660     CdlNode node = expr->references[arg0.reference_index].get_destination();
661     if (0 != node) {
662         CdlValuable valuable    = dynamic_cast<CdlValuable>(node);
663         if (0 != valuable) {
664             // OK, we have found a valuable. Is it already enabled?
665             // Does it have a boolean component? Is it modifiable? Has
666             // it already been modified by the user in this transaction?
667             if (goal == valuable->is_enabled()) {
668                 result = true;
669             } else {
670                 CdlValueFlavor flavor = valuable->get_flavor();
671                 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
672                     if (valuable->is_modifiable()) {
673                         if (!transaction->changed_by_user(valuable)) {
674                             // We have a modifiable option and want to set the enabled flag.
675                             // However we do not want to lose the current data part - unless
676                             // some other constraint has caused that to be set.
677                             const CdlValue& old_value   = transaction->get_whole_value(valuable);
678                             CdlValue        new_value   = old_value;
679                             if (!old_value.has_source(CdlValueSource_Inferred)) {
680                                 CdlSimpleValue simple_value = old_value.get_simple_value(CdlValueSource_Current);
681                                 new_value.set_value(simple_value, CdlValueSource_Inferred);
682                             }
683                             new_value.set_enabled(goal, CdlValueSource_Inferred);
684                             new_value.set_source(CdlValueSource_Inferred);
685                             transaction->set_whole_value(valuable, old_value, new_value);
686                             result = transaction->resolve_recursion(level);
687                         }
688                     }
689                 }
690             }
691         }
692     }
693     
694     CYG_REPORT_RETVAL(result);
695     return result;
696 }
697
698 static CdlFunction is_enabled("is_enabled", 1, &is_enabled_check, &is_enabled_eval,
699                               &is_enabled_infer_bool, CdlFunction::null_infer_value);
700
701 //}}}
702 //{{{  get_data()                       
703
704 // ----------------------------------------------------------------------------
705 // get_data(x)
706 // Returns "0" if the specified option is not enabled, otherwise
707 // the current data part fo the value. The active/inactive and the
708 // enabled states are ignored. This function takes a single argument
709 // which must be a reference.
710
711 static void
712 get_data_check(CdlExpression expr, const CdlSubexpression& subexpr)
713 {
714     CYG_REPORT_FUNCNAME("get_data_check");
715     CYG_REPORT_FUNCARG2XV(expr, &subexpr);
716
717     CdlSubexpression& arg0 = expr->sub_expressions[subexpr.args[0]];
718     if (CdlExprOp_Reference != arg0.op) {
719         throw CdlParseException(std::string("The argument to get_data() should be a reference to a configuration option.\n") +
720                                 CdlParse::get_expression_error_location());
721     }
722     
723     CYG_REPORT_RETURN();
724 }
725
726 static void
727 get_data_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
728 {
729     CYG_REPORT_FUNCNAME("get_data_eval");
730     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
731     CYG_PRECONDITION_CLASSOC(context);
732     CYG_PRECONDITION_CLASSC(expr);
733
734     CdlSubexpression arg0 = expr->sub_expressions[subexpr.args[0]];
735     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
736
737     CdlValuable valuable = context.resolve_valuable_reference(expr, arg0.reference_index);
738     if (0 != valuable) {
739         if (0 != context.transaction) {
740             result = valuable->get_value(context.transaction);
741         } else {
742             result = valuable->get_value();
743         }
744     } else {
745         result = false;
746     }
747     CYG_REPORT_RETURN();
748 }
749
750 static bool
751 get_data_infer_value(CdlTransaction transaction, CdlExpression expr, unsigned int index,  CdlSimpleValue& goal, int level)
752 {
753     CYG_REPORT_FUNCNAMETYPE("get_data_infer_value", "result %d");
754     CYG_REPORT_FUNCARG5XV(transaction, expr, index, &goal, level);
755
756     bool result = false;
757
758     CdlSubexpression subexpr    = expr->sub_expressions[index];
759     CdlSubexpression arg0       = expr->sub_expressions[subexpr.args[0]];
760     CYG_ASSERTC(CdlExprOp_Reference == arg0.op);
761
762     CdlNode node = expr->references[arg0.reference_index].get_destination();
763     if (0 != node) {
764         CdlValuable valuable    = dynamic_cast<CdlValuable>(node);
765         if (0 != valuable) {
766             // OK, we have found a valuable. Does it have a data component?
767             // Does it already have the right value. Is it modifiable? Has
768             // it already been modified by the user in this transaction?
769             CdlValueFlavor flavor = valuable->get_flavor();
770             if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
771                 CdlSimpleValue current_value = valuable->get_simple_value(transaction);
772                 if (goal != current_value) {
773                     if (valuable->is_modifiable()) {
774                         if (!transaction->changed_by_user(valuable)) {
775                             // We have a modifiable option and want to set the data part.
776                             // However we do not want to lose the enabled part - unless
777                             // some other constraint has caused that to be set.
778                             const CdlValue& old_value   = transaction->get_whole_value(valuable);
779                             CdlValue        new_value   = old_value;
780                             if (!old_value.has_source(CdlValueSource_Inferred)) {
781                                 new_value.set_enabled(old_value.is_enabled(), CdlValueSource_Inferred);
782                             }
783                             new_value.set_value(goal, CdlValueSource_Inferred);
784                             new_value.set_source(CdlValueSource_Inferred);
785                             transaction->set_whole_value(valuable, old_value, new_value);
786                             result = transaction->resolve_recursion(level);
787                         }
788                     }
789                 }
790             }
791         }
792     }
793     
794     CYG_REPORT_RETVAL(result);
795     return result;
796 }
797
798 static CdlFunction get_data("get_data", 1, &get_data_check, &get_data_eval,
799                             CdlFunction::null_infer_bool, &get_data_infer_value);
800
801 //}}}
802 //{{{  version_cmp()                    
803
804 // ----------------------------------------------------------------------------
805 // version_cmp(a, b)
806 // Evaluate both arguments, interpret them as version strings, and then
807 // return -1, 0 or 1.
808
809 static void
810 version_cmp_eval(CdlEvalContext& context, CdlExpression expr, const CdlSubexpression& subexpr, CdlSimpleValue& result)
811 {
812     CYG_REPORT_FUNCNAME("version_cmp_eval");
813     CYG_REPORT_FUNCARG4XV(&context, expr, &subexpr, &result);
814     CYG_PRECONDITION_CLASSOC(context);
815     CYG_PRECONDITION_CLASSC(expr);
816
817     CdlSimpleValue      arg0;
818     CdlSimpleValue      arg1;
819     expr->eval_subexpression(context, subexpr.args[0], arg0);
820     expr->eval_subexpression(context, subexpr.args[1], arg1);
821
822     result = (cdl_int) Cdl::compare_versions(arg0.get_value(), arg1.get_value());
823     
824     CYG_REPORT_RETURN();
825 }
826
827 static CdlFunction version_cmp("version_cmp", 2, CdlFunction::null_check, &version_cmp_eval,
828                                CdlFunction::null_infer_bool, CdlFunction::null_infer_value);
829
830 //}}}