source: SVN/cambria/redboot/host/libcdl/func.cxx @ 1

Last change on this file since 1 was 1, checked in by Tim Harvey, 2 years ago

restored latest version of files from server backup

Signed-off-by: Tim Harvey <tharvey@…>

File size: 30.7 KB
Line 
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// ----------------------------------------------------------------------------
66int CdlFunction::next_id        = 1;
67std::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.
71void (*CdlFunction::null_check)(CdlExpression, const CdlSubexpression&) =
72     (void (*)(CdlExpression, const CdlSubexpression&)) 0;
73bool (*CdlFunction::null_infer_bool)(CdlTransaction, CdlExpression, unsigned int, bool, int) =
74     (bool (*)(CdlTransaction, CdlExpression, unsigned int, bool, int)) 0;
75bool (*CdlFunction::null_infer_value)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int) =
76     (bool (*)(CdlTransaction, CdlExpression, unsigned int, CdlSimpleValue&, int)) 0;
77
78
79CdlFunction::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
95CdlFunction::~CdlFunction()
96{
97}
98
99bool
100CdlFunction::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
118std::string
119CdlFunction::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
138int
139CdlFunction::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
157void
158CdlFunction::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
178void
179CdlFunction::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
197bool
198CdlFunction::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
221bool
222CdlFunction::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
258static std::string::size_type
259is_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
313static void
314is_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.
333static bool
334is_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
394static 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
406static void
407is_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.
425static bool
426is_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
483static 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
496static void
497is_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
511static void
512is_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
526static 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
537static void
538is_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
552static void
553is_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
572static bool
573is_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
597static 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
609static void
610is_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
624static void
625is_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
648static bool
649is_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
698static 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
711static void
712get_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
726static void
727get_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
750static bool
751get_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
798static 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
809static void
810version_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
827static CdlFunction version_cmp("version_cmp", 2, CdlFunction::null_check, &version_cmp_eval,
828                               CdlFunction::null_infer_bool, CdlFunction::null_infer_value);
829
830//}}}
Note: See TracBrowser for help on using the repository browser.