source: trunk/third/bonobo-activation/server/activation-context-query.c @ 18311

Revision 18311, 25.8 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18310, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
2/*
3 *  oafd: OAF CORBA dameon.
4 *
5 *  Copyright (C) 1999, 2000 Red Hat, Inc.
6 *  Copyright (C) 1999, 2000 Eazel, Inc.
7 *
8 *  This library is free software; you can redistribute it and/or
9 *  modify it under the terms of the GNU General Public License as
10 *  published by the Free Software Foundation; either version 2 of the
11 *  License, or (at your option) any later version.
12 *
13 *  This library is distributed in the hope that it will be useful,
14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 *  General Public License for more details.
17 *
18 *  You should have received a copy of the GNU General Public License
19 *  along with this library; if not, write to the Free Software
20 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 *  Authors: Elliot Lee <sopwith@redhat.com>,
23 *
24 */
25
26/*
27   Likely bugs: Forgetting to initialize QueryExprConst.needs_free = crash
28*/
29#include <stdio.h>
30#include <string.h>
31
32#include "activation-context-query.h"
33#include "activation-context-query-parser.h"
34
35static QueryExpr *
36qexp_new (void)
37{
38        QueryExpr *retval = g_new (QueryExpr, 1);
39
40        retval->have_cached_value = FALSE;
41        retval->has_fields = TRUE;
42
43        return retval;
44}
45
46void
47qexp_free (QueryExpr * qexp)
48{
49        if (!qexp)
50                return;
51
52        switch (qexp->type) {
53        case EXPR_FUNCTION:
54                g_free (qexp->u.function_value.func_name);
55                g_slist_foreach (qexp->u.function_value.arguments,
56                                 (GFunc) qexp_free, NULL);
57                g_slist_free (qexp->u.function_value.arguments);
58                break;
59        case EXPR_VARIABLE:
60                g_free (qexp->u.var_value);
61                break;
62        case EXPR_ID:
63                g_free (qexp->u.id_value);
64                break;
65        case EXPR_BINOP:
66                qexp_free (qexp->u.binop_value.op1);
67                qexp_free (qexp->u.binop_value.op2);
68                break;
69        case EXPR_UNOP:
70                qexp_free (qexp->u.unop_value.op);
71                break;
72        case EXPR_CONSTANT:
73                if (qexp->u.constant_value.value_known) {
74                        switch (qexp->u.constant_value.type) {
75                        case CONST_STRING:
76                                g_free (qexp->u.constant_value.u.v_string);
77                                break;
78                        case CONST_STRINGV:
79                                g_strfreev (qexp->u.constant_value.
80                                            u.v_stringv);
81                                break;
82                        default:
83                                break;
84                        }
85                }
86                break;
87        }
88
89        g_free (qexp);
90}
91
92QueryExpr *
93qexp_binop_new (QueryExpr * op1, int operand, QueryExpr * op2)
94{
95        QueryExpr *retval = qexp_new ();
96        int optype;
97
98        switch (operand) {
99        case P_MULTIPLY:
100                optype = OP_MULTIPLY;
101                break;
102        case P_DIVIDE:
103                optype = OP_DIVIDE;
104                break;
105        case P_SUBTRACT:
106                optype = OP_SUBTRACT;
107                break;
108        case P_ADD:
109                optype = OP_ADD;
110                break;
111        case P_EQ:
112                optype = OP_EQ;
113                break;
114        case P_NEQ:
115                optype = OP_NEQ;
116                break;
117        case P_LEQ:
118                optype = OP_LEQ;
119                break;
120        case P_GEQ:
121                optype = OP_GEQ;
122                break;
123        case P_GT:
124                optype = OP_GT;
125                break;
126        case P_LT:
127                optype = OP_LT;
128                break;
129        case P_OR:
130                optype = OP_OR;
131                break;
132        case P_AND:
133                optype = OP_AND;
134                break;
135        case P_XOR:
136                optype = OP_XOR;
137                break;
138        default:
139                g_assert_not_reached ();
140                optype = 0;
141                break;
142        }
143
144        retval->u.binop_value.type = optype;
145        retval->u.binop_value.op1 = op1;
146        retval->u.binop_value.op2 = op2;
147
148        retval->type = EXPR_BINOP;
149        retval->has_fields = op1->has_fields || op2->has_fields;
150
151        return retval;
152}
153
154QueryExpr *
155qexp_unop_new (int operand, QueryExpr * op)
156{
157        QueryExpr *retval = qexp_new ();
158        int optype;
159
160        switch (operand) {
161        case P_SUBTRACT:
162                optype = OP_SUBTRACT;
163                break;
164        case P_NOT:
165                optype = OP_NOT;
166                break;
167        default:
168                g_assert_not_reached ();
169                optype = 0;
170                break;
171        }
172
173        retval->type = EXPR_UNOP;
174        retval->u.unop_value.type = optype;
175        retval->u.unop_value.op = op;
176
177        retval->has_fields = op->has_fields;
178
179        return retval;
180}
181
182QueryExpr *
183qexp_function_new (char *name, GSList * exprlist)
184{
185        GSList *cur;
186        QueryExpr *retval = qexp_new ();
187
188        retval->type = EXPR_FUNCTION;
189        retval->u.function_value.func_name = name;
190        retval->u.function_value.arguments = exprlist;
191
192        cur = exprlist;
193       
194        while (cur != NULL && !((QueryExpr *) cur->data)->has_fields) {
195                cur = cur->next;
196        }
197
198        retval->has_fields = cur ? TRUE : FALSE;
199
200        return retval;
201}
202
203QueryExpr *
204qexp_variable_new (char *name)
205{
206        QueryExpr *retval = qexp_new ();
207
208        retval->type = EXPR_VARIABLE;
209        retval->u.var_value = name;
210
211        retval->has_fields = FALSE;
212
213        return retval;
214}
215
216QueryExpr *
217qexp_id_new (char *name)
218{
219        QueryExpr *retval = qexp_new ();
220
221        retval->type = EXPR_ID;
222        retval->u.var_value = name;
223
224        retval->has_fields = TRUE;
225
226        return retval;
227}
228
229QueryExpr *
230qexp_constant_new (QueryExprConst setme)
231{
232        QueryExpr *retval = qexp_new ();
233
234        retval->type = EXPR_CONSTANT;
235        retval->u.constant_value = setme;
236        retval->u.constant_value.value_known = TRUE;
237
238        retval->has_fields = FALSE;
239
240        return retval;
241}
242
243void
244qexp_dump (QueryExpr * exp)
245{
246        switch (exp->type) {
247        case EXPR_FUNCTION:
248                {
249                        GSList *cur;
250
251                        g_print ("%s(", exp->u.function_value.func_name);
252                        for (cur = exp->u.function_value.arguments; cur;
253                             cur = cur->next) {
254                                qexp_dump (cur->data);
255                                if (cur->next)
256                                        g_print (", ");
257                        }
258                        g_print (")");
259                }
260                break;
261        case EXPR_VARIABLE:
262                g_print ("$%s", exp->u.var_value);
263                break;
264        case EXPR_ID:
265                g_print ("%s", exp->u.id_value);
266                break;
267        case EXPR_BINOP:
268                {
269                        char *opc;
270
271                        g_print ("(");
272                        qexp_dump (exp->u.binop_value.op1);
273                        g_print (")");
274                        switch (exp->u.binop_value.type) {
275                        case OP_EQ:
276                                opc = "=";
277                                break;
278                        case OP_NEQ:
279                                opc = "!=";
280                                break;
281                        case OP_LEQ:
282                                opc = "<=";
283                                break;
284                        case OP_GEQ:
285                                opc = ">=";
286                                break;
287                        case OP_LT:
288                                opc = "<";
289                                break;
290                        case OP_GT:
291                                opc = ">";
292                                break;
293                        case OP_OR:
294                                opc = "||";
295                                break;
296                        case OP_AND:
297                                opc = "&&";
298                                break;
299                        case OP_MULTIPLY:
300                                opc = "*";
301                                break;
302                        case OP_DIVIDE:
303                                opc = "/";
304                                break;
305                        case OP_ADD:
306                                opc = "+";
307                                break;
308                        case OP_SUBTRACT:
309                                opc = "-";
310                                break;
311                        case OP_XOR:
312                                opc = "^";
313                                break;
314                        default:
315                                opc = NULL;
316                                break;
317                        }
318                        g_print (" %s (", opc);
319                        qexp_dump (exp->u.binop_value.op2);
320                        g_print (")");
321                }
322                break;
323        case EXPR_UNOP:
324                switch (exp->u.unop_value.type) {
325                case OP_NOT:
326                        g_print ("~(");
327                        break;
328                case OP_NEGATE:
329                        g_print ("-(");
330                        break;
331                }
332                qexp_dump (exp->u.unop_value.op);
333                g_print (")");
334                break;
335        case EXPR_CONSTANT:
336                qexp_constant_dump (&exp->u.constant_value);
337                break;
338        default:
339                g_error ("Unknown exp type %d", exp->type);
340                break;
341        }
342}
343
344void
345qexp_constant_dump (QueryExprConst * c)
346{
347        if (c->value_known) {
348                switch (c->type) {
349                case CONST_STRINGV:
350                        {
351                                int i;
352
353                                g_print ("[");
354                                for (i = 0; c->u.v_stringv[i]; i++) {
355                                        g_print ("'%s'", c->u.v_stringv[i]);
356                                        if (c->u.v_stringv[i + 1])
357                                                g_print (", ");
358                                }
359                                g_print ("]");
360                        }
361                        break;
362                case CONST_STRING:
363                        g_print ("'%s'", c->u.v_string);
364                        break;
365                case CONST_NUMBER:
366                        g_print ("%f", c->u.v_number);
367                        break;
368                case CONST_BOOLEAN:
369                        g_print ("%s", c->u.v_boolean ? "TRUE" : "FALSE");
370                        break;
371                }
372        } else
373                g_print ("??");
374}
375
376/* Returns a value suitable for use in boolean expressions */
377static gboolean
378qexp_constant_bool (const QueryExprConst * c)
379{
380        if (c->value_known)
381                switch (c->type) {
382                case CONST_BOOLEAN:
383                        return c->u.v_boolean;
384                case CONST_NUMBER:
385                        return (c->u.v_number != 0.0);
386                case CONST_STRING:
387                        return (c->u.v_string != NULL);
388                case CONST_STRINGV:
389                        return (c->u.v_stringv != NULL);
390                }
391
392        return FALSE;
393}
394
395gint
396qexp_constant_compare (const QueryExprConst * c1, const QueryExprConst * c2)
397{
398        if (c1->value_known && c2->value_known) {
399                g_return_val_if_fail (c1->type == c2->type, 0);
400
401                switch (c1->type) {
402                case CONST_STRING:
403                        return strcmp (c1->u.v_string, c2->u.v_string);
404                        break;
405                case CONST_BOOLEAN:
406                        if (c1->u.v_boolean && !c2->u.v_boolean)
407                                return -1;
408                        else if (c2->u.v_boolean && !c1->u.v_boolean)
409                                return 1;
410                        else
411                                return 0;
412                        break;
413                case CONST_NUMBER:
414                        {
415                                if (c2->u.v_number > c1->u.v_number)
416                                        return 1;
417                                else if (c2->u.v_number < c1->u.v_number)
418                                        return -1;
419                                else
420                                        return 0;
421                        }
422                        break;
423                default:
424                        g_assert_not_reached ();
425                        break;
426                }
427        } else if (c1->value_known)
428                return -1;
429        else if (c2->value_known)
430                return 1;
431
432        return 0;
433}
434
435#define qexp_constant_unuse(c) if ((c).needs_free && (c).value_known) qexp_constant_free(&(c))
436static void
437qexp_constant_free (const QueryExprConst * c)
438{
439        switch (c->type) {
440        case CONST_STRING:
441                g_free (c->u.v_string);
442                break;
443        case CONST_STRINGV:
444                g_strfreev (c->u.v_stringv);
445                break;
446        default:
447                break;
448        }
449}
450
451
452/********************************************* Now the fun stuff *****************************************/
453
454/******* handling functions *********/
455
456
457typedef QueryExprConst (*QueryExprEvalFunc) (Bonobo_ServerInfo * si,
458                                             QueryExpr * e,
459                                             QueryContext * qctx);
460/* A table of the functions that can be used in queries */
461typedef struct
462{
463        const char *name;
464        QueryExprEvalFunc efunc;
465        int min_args, max_args;
466}
467QueryExprFuncInfo;
468
469static QueryExprConst qexp_func_has_one (Bonobo_ServerInfo * si, QueryExpr * e,
470                                         QueryContext * qctx);
471static QueryExprConst qexp_func_has_all (Bonobo_ServerInfo * si, QueryExpr * e,
472                                         QueryContext * qctx);
473static QueryExprConst qexp_func_has (Bonobo_ServerInfo * si, QueryExpr * e,
474                                     QueryContext * qctx);
475
476static QueryExprConst qexp_func_prefer_by_list_order (Bonobo_ServerInfo * si, QueryExpr * e,
477                                                      QueryContext * qctx);
478
479static QueryExprConst qexp_func_defined (Bonobo_ServerInfo * si, QueryExpr * e,
480                                         QueryContext * qctx);
481static QueryExprConst qexp_func_max (Bonobo_ServerInfo * si, QueryExpr * e,
482                                     QueryContext * qctx);
483static QueryExprConst qexp_func_min (Bonobo_ServerInfo * si, QueryExpr * e,
484                                     QueryContext * qctx);
485
486static const QueryExprFuncInfo qexp_func_impls[] = {
487        {"has_one", qexp_func_has_one, 2},
488        {"has_all", qexp_func_has_all, 2},
489        {"has", qexp_func_has, 2},
490        {"prefer_by_list_order", qexp_func_prefer_by_list_order, 2},
491        {"defined", qexp_func_defined, 1},
492        {"max", qexp_func_max, 1},
493        {"min", qexp_func_min, 1},
494        {NULL}
495};
496
497static QueryExprConst
498qexp_evaluate_function (Bonobo_ServerInfo * si, QueryExpr * e,
499                        QueryContext * qctx)
500{
501        QueryExprConst retval;
502        const char *func_name;
503        int i, n, max;
504        const QueryExprFuncInfo *fi;
505
506        func_name = e->u.function_value.func_name;
507
508        for (i = 0; qexp_func_impls[i].name; i++) {
509                if (!g_ascii_strcasecmp (func_name, qexp_func_impls[i].name))
510                        break;
511        }
512
513        fi = &qexp_func_impls[i];
514        if (!fi->name) {
515                retval.value_known = FALSE;
516                retval.needs_free = FALSE;
517                g_warning ("Invalid function name '%s'", func_name);
518                return retval;
519        }
520
521        n = g_slist_length (e->u.function_value.arguments);
522
523        max = fi->max_args;
524        if (max < fi->min_args)
525                max = fi->min_args;
526        if ((n < fi->min_args) || (n > max)) {
527                g_warning
528                        ("Incorrect argument count to function '%s': got %d, need between %d and %d",
529                         func_name, n, fi->min_args, max);
530        }
531
532        return fi->efunc (si, e, qctx);
533
534}
535
536static QueryExprConst
537qexp_func_has_one (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
538{
539        QueryExprConst retval, v1, v2;
540        int i, j;
541        gboolean found;
542        char **check_one, **check_two;
543
544        v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx);
545        v2 =
546                qexp_evaluate (si, e->u.function_value.arguments->next->data,
547                               qctx);
548
549        retval.value_known = TRUE;
550
551        if (!v1.value_known || !v2.value_known) {
552                retval.type = CONST_BOOLEAN;
553                retval.u.v_boolean = FALSE;
554        } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRINGV) {
555                retval.value_known = FALSE;
556        } else {
557                found = FALSE;
558
559                check_one = v1.u.v_stringv;
560                check_two = v2.u.v_stringv;
561
562                for (i = j = 0; check_one[i]; i++) {
563                        for (j = 0; check_two[j]; j++) {
564                                if (!strcmp (check_one[i], check_two[j])) {
565                                        found = TRUE;
566                                        break;
567                                }
568                        }
569                }
570
571                retval.type = CONST_BOOLEAN;
572                retval.u.v_boolean = found;
573        }
574
575        retval.needs_free = FALSE;
576        qexp_constant_unuse (v1);
577        qexp_constant_unuse (v2);
578
579        return retval;
580}
581
582static QueryExprConst
583qexp_func_has_all (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
584{
585        QueryExprConst retval, v1, v2;
586        int i, j;
587        char **check_one, **check_two;
588
589        v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx);
590        v2 =
591                qexp_evaluate (si, e->u.function_value.arguments->next->data,
592                               qctx);
593
594        retval.value_known = TRUE;
595
596        if (!v1.value_known || !v2.value_known) {
597                retval.type = CONST_BOOLEAN;
598                retval.u.v_boolean = FALSE;
599        } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRINGV) {
600                retval.value_known = FALSE;
601        } else {
602                check_one = v1.u.v_stringv;
603                check_two = v2.u.v_stringv;
604
605                for (i = j = 0; check_two[j] && check_one[i]; j++) {
606                        for (i = 0; check_one[i]; i++) {
607                                if (!strcmp (check_two[j], check_one[i]))
608                                        break;
609                        }
610                }
611
612                retval.type = CONST_BOOLEAN;
613                retval.u.v_boolean = check_one[i] ? TRUE : FALSE;
614        }
615
616        retval.needs_free = FALSE;
617
618        qexp_constant_unuse (v1);
619        qexp_constant_unuse (v2);
620
621        return retval;
622}
623
624static QueryExprConst
625qexp_func_has (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
626{
627        QueryExprConst retval, v1, v2;
628        char **check_one, *check_two;
629        int i;
630
631        v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx);
632        v2 =
633                qexp_evaluate (si, e->u.function_value.arguments->next->data,
634                               qctx);
635
636        retval.value_known = TRUE;
637
638        if (!v1.value_known || !v2.value_known) {
639                retval.type = CONST_BOOLEAN;
640                retval.u.v_boolean = FALSE;
641        } else if (v1.type != CONST_STRINGV || v2.type != CONST_STRING) {
642                retval.value_known = FALSE;
643        } else {
644                check_one = v1.u.v_stringv;
645                check_two = v2.u.v_string;
646
647                for (i = 0; check_one[i]; i++) {
648                        if (!strcmp (check_one[i], check_two))
649                                break;
650                }
651
652                retval.type = CONST_BOOLEAN;
653                retval.u.v_boolean = check_one[i] ? TRUE : FALSE;
654        }
655
656        retval.needs_free = FALSE;
657
658        qexp_constant_unuse (v1);
659        qexp_constant_unuse (v2);
660
661        return retval;
662}
663
664
665
666static QueryExprConst
667qexp_func_prefer_by_list_order (Bonobo_ServerInfo *si,
668                                QueryExpr *e,
669                                QueryContext *qctx)
670{
671        QueryExprConst retval, item, list;
672        char **check_one, *check_two;
673        int i;
674        int position;
675
676        item = qexp_evaluate (si, e->u.function_value.arguments->data, qctx);
677        list = qexp_evaluate (si, e->u.function_value.arguments->next->data, qctx);
678
679        retval.value_known = TRUE;
680
681        if (!item.value_known || !list.value_known) {
682                retval.type = CONST_BOOLEAN;
683                retval.u.v_boolean = FALSE;
684        } else if (item.type != CONST_STRING || list.type != CONST_STRINGV) {
685                retval.value_known = FALSE;
686        } else {
687                position = -1;
688               
689                check_one = list.u.v_stringv;
690                check_two = item.u.v_string;
691
692                for (i = 0; check_one[i] != NULL; i++) {
693                        if (position == -1 &&
694                            strcmp (check_one[i], check_two) == 0) {
695                                position = i;
696                        }
697                }
698
699                if (position != -1) {
700                        position = i - position;
701                }
702
703                retval.type = CONST_NUMBER;
704                retval.u.v_number = position;
705        }
706
707        retval.needs_free = FALSE;
708
709        qexp_constant_unuse (item);
710        qexp_constant_unuse (list);
711
712        return retval;
713}
714
715
716static QueryExprConst
717qexp_func_defined (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
718{
719        QueryExprConst retval, v1;
720
721        v1 = qexp_evaluate (si, e->u.function_value.arguments->data, qctx);
722
723        retval.value_known = TRUE;
724
725        retval.type = CONST_BOOLEAN;
726
727        retval.u.v_boolean = v1.value_known ? TRUE : FALSE;
728
729        retval.needs_free = FALSE;
730
731        qexp_constant_unuse (v1);
732
733        return retval;
734}
735
736
737static QueryExprConst
738qexp_func_max (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
739{
740        int i;
741        QueryExprConst max_val_so_far;
742
743        max_val_so_far.value_known = FALSE;
744
745        for (i = 0; i < qctx->nservers; i++) {
746                QueryExprConst new_val;
747
748                new_val =
749                        qexp_evaluate (qctx->sil[i],
750                                       e->u.function_value.arguments->data,
751                                       qctx);
752                if (qexp_constant_compare (&max_val_so_far, &new_val) > 0)
753                        max_val_so_far = new_val;
754        }
755
756        /* The value of this function never changes on a per-record basis, so we never have to revaluate it */
757        e->has_fields = FALSE;
758
759        return max_val_so_far;
760}
761
762static QueryExprConst
763qexp_func_min (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
764{
765        int i;
766        QueryExprConst min_val_so_far;
767
768        min_val_so_far.value_known = FALSE;
769
770        for (i = 0; i < qctx->nservers; i++) {
771                QueryExprConst new_val;
772
773                new_val =
774                        qexp_evaluate (qctx->sil[i],
775                                       e->u.function_value.arguments->data,
776                                       qctx);
777                if (qexp_constant_compare (&min_val_so_far, &new_val) > 0)
778                        min_val_so_far = new_val;
779        }
780
781        /* see comment in qexp_func_max */
782        e->has_fields = FALSE;
783
784        return min_val_so_far;
785}
786
787/********** Variables *******/
788
789static QueryExprConst
790qexp_evaluate_variable (Bonobo_ServerInfo * si, QueryExpr * e,
791                        QueryContext * qctx)
792{
793        QueryExprConst retval;
794
795        retval.value_known = FALSE;
796
797        if (qctx->cctx) {
798                CORBA_Environment ev;
799                CORBA_NVList nvout;
800
801                CORBA_exception_init (&ev);
802                CORBA_Context_get_values (qctx->cctx, NULL, 0, e->u.var_value,
803                                          &nvout, &ev);
804
805                /* FIXME bugzilla.eazel.com 2732: non-standard - I
806                 * screwed up the NVList implementation in ORBit */
807
808                if (ev._major == CORBA_NO_EXCEPTION) {
809                        if (nvout->list->len > 0) {
810                                CORBA_NamedValue *nv;
811                                retval.value_known = TRUE;
812                                retval.type = CONST_STRING;
813                                nv =
814                                        &g_array_index (nvout->list,
815                                                        CORBA_NamedValue, 0);
816                                retval.u.v_string =
817                                        g_strdup (*(char **) nv->
818                                                  argument._value);
819                                retval.needs_free = TRUE;
820                        } else
821                                g_warning ("Unknown variable %s",
822                                           e->u.var_value);
823
824                        CORBA_NVList_free (nvout, &ev);
825                } else
826                        g_warning ("Unknown variable %s", e->u.var_value);
827
828                CORBA_exception_free (&ev);
829        } else
830                g_warning ("Unknown variable %s", e->u.var_value);
831
832        return retval;
833}
834
835/********* fields ***********/
836static QueryExprConst
837qexp_evaluate_id (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
838{
839        QueryExprConst retval;
840
841        retval.value_known = retval.needs_free = FALSE;
842
843        if (si) {
844                retval.value_known = TRUE;
845                retval.type = CONST_STRING;
846                if (!g_ascii_strcasecmp (e->u.id_value, "location_info"))
847                        retval.u.v_string = si->location_info;
848                else if (!g_ascii_strcasecmp (e->u.id_value, "server_type"))
849                        retval.u.v_string = si->server_type;
850                else if (!g_ascii_strcasecmp (e->u.id_value, "iid"))
851                        retval.u.v_string = si->iid;
852                else if (!g_ascii_strcasecmp (e->u.id_value, "username"))
853                        retval.u.v_string = si->username;
854                else if (!g_ascii_strcasecmp (e->u.id_value, "hostname"))
855                        retval.u.v_string = si->hostname;
856                else if (!g_ascii_strcasecmp (e->u.id_value, "domain"))
857                        retval.u.v_string = si->domain;
858                else {
859                        int i;
860                        for (i = 0; i < si->props._length; i++) {
861                                if (!strcmp
862                                    (e->u.id_value,
863                                     si->props._buffer[i].name)) break;
864                        }
865
866                        retval.value_known = FALSE;
867
868                        if (i < si->props._length) {
869                                Bonobo_ActivationPropertyValue *av;
870
871                                av = &si->props._buffer[i].v;
872
873                                switch (av->_d) {
874                                case Bonobo_ACTIVATION_P_STRING:
875                                        retval.type = CONST_STRING;
876                                        retval.u.v_string =
877                                                av->_u.value_string;
878                                        break;
879                                case Bonobo_ACTIVATION_P_NUMBER:
880                                        retval.type = CONST_NUMBER;
881                                        retval.u.v_number =
882                                                av->_u.value_number;
883                                        break;
884                                case Bonobo_ACTIVATION_P_BOOLEAN:
885                                        retval.type = CONST_BOOLEAN;
886                                        retval.u.v_boolean =
887                                                av->_u.value_boolean;
888                                        break;
889                                case Bonobo_ACTIVATION_P_STRINGV:
890                                        {
891                                                /* FIXME bugzilla.eazel.com 2729: it would be nice to replace the
892                                                 * NULL-terminated string arrays with
893                                                 * CORBA_sequence_string all over
894                                                 */
895
896                                                int i;
897                                                retval.type = CONST_STRINGV;
898
899                                                retval.needs_free = TRUE;
900
901                                                retval.u.v_stringv =
902                                                        g_malloc (sizeof
903                                                                  (char *) *
904                                                                  (av->
905                                                                   _u.value_stringv._length
906                                                                   + 1));
907                                                for (i = 0;
908                                                     i <
909                                                     av->_u.
910                                                     value_stringv._length;
911                                                     i++) retval.
912                                                                u.v_stringv[i]
913                                                                =
914                                                                g_strdup
915                                                                (av->_u.value_stringv._buffer
916                                                                 [i]);
917                                                retval.u.v_stringv[i] = NULL;
918                                        }
919                                        break;
920                                }
921
922                                retval.value_known = TRUE;
923                        } else if (qctx->id_evaluator)
924                                retval =
925                                        qctx->id_evaluator (si, e->u.id_value,
926                                                            qctx);
927                }
928        }
929
930        return retval;
931}
932
933/********* binary operators *********/
934
935static QueryExprConst
936qexp_evaluate_binop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
937{
938        QueryExprConst retval, v1, v2;
939        gboolean negate_result = FALSE;
940
941        v2.value_known = FALSE; /* To make sure that qexp_constant_unuse works properly if we short-circuit */
942
943        retval.value_known = TRUE;
944        retval.needs_free = FALSE;
945
946        v1 = qexp_evaluate (si, e->u.binop_value.op1, qctx);
947
948        /* Perform short-circuiting */
949        switch (e->u.binop_value.type) {
950        case OP_OR:
951                if (v1.value_known && qexp_constant_bool (&v1)) {
952                        retval.type = CONST_BOOLEAN;
953                        retval.u.v_boolean = TRUE;
954                        qexp_constant_unuse (v1);
955                        return retval;
956                }
957                break;
958        case OP_AND:
959                if (v1.value_known && !qexp_constant_bool (&v1)) {
960                        retval.type = CONST_BOOLEAN;
961                        retval.u.v_boolean = FALSE;
962                        qexp_constant_unuse (v1);
963                        return retval;
964                }
965                break;
966        default:
967                break;
968        }
969
970        v2 = qexp_evaluate (si, e->u.binop_value.op2, qctx);
971
972        retval.value_known = TRUE;
973
974        switch (e->u.binop_value.type) {
975        case OP_NEQ:
976                negate_result = TRUE;
977        case OP_EQ:
978                retval.type = CONST_BOOLEAN;
979                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) == 0;
980                break;
981        case OP_GEQ:
982                negate_result = TRUE;
983        case OP_LT:
984                retval.type = CONST_BOOLEAN;
985                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) < 0;
986                break;
987        case OP_LEQ:
988                negate_result = TRUE;
989        case OP_GT:
990                retval.type = CONST_BOOLEAN;
991                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) > 0;
992                break;
993        case OP_OR:
994                retval.type = CONST_BOOLEAN;
995                retval.u.v_boolean = qexp_constant_bool (&v1)
996                        || qexp_constant_bool (&v2);
997                break;
998        case OP_AND:
999                retval.type = CONST_BOOLEAN;
1000                retval.u.v_boolean = qexp_constant_bool (&v1)
1001                        && qexp_constant_bool (&v2);
1002                break;
1003        case OP_MULTIPLY:
1004                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1005                        retval.value_known = FALSE;
1006                else {
1007                        retval.type = CONST_NUMBER;
1008                        retval.u.v_number = v1.u.v_number * v2.u.v_number;
1009                }
1010                break;
1011        case OP_DIVIDE:
1012                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1013                        retval.value_known = FALSE;
1014                else {
1015                        retval.type = CONST_NUMBER;
1016                        if (v2.u.v_number == 0.0)
1017                                retval.value_known = FALSE;
1018                        else
1019                                retval.u.v_number =
1020                                        v1.u.v_number / v2.u.v_number;
1021                }
1022                break;
1023        case OP_ADD:
1024                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1025                        retval.value_known = FALSE;
1026                else {
1027                        retval.type = CONST_NUMBER;
1028                        retval.u.v_number = v1.u.v_number + v2.u.v_number;
1029                }
1030                break;
1031        case OP_SUBTRACT:
1032                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1033                        retval.value_known = FALSE;
1034                else {
1035                        retval.type = CONST_NUMBER;
1036                        retval.u.v_number = v1.u.v_number - v2.u.v_number;
1037                }
1038                break;
1039        case OP_XOR:
1040                retval.type = CONST_BOOLEAN;
1041                retval.u.v_boolean =
1042                        qexp_constant_bool (&v1) ^ qexp_constant_bool (&v2);
1043                break;
1044        }
1045
1046        if (negate_result)
1047                retval.u.v_boolean = !retval.u.v_boolean;
1048
1049        qexp_constant_unuse (v1);
1050        qexp_constant_unuse (v2);
1051
1052        return retval;
1053}
1054
1055/********** unary operators **********/
1056static QueryExprConst
1057qexp_evaluate_unop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1058{
1059        QueryExprConst retval, v1;
1060
1061        retval.value_known = TRUE;
1062
1063        v1 = qexp_evaluate (si, e->u.unop_value.op, qctx);
1064        switch (e->u.unop_value.type) {
1065        case OP_NOT:
1066                retval.type = CONST_BOOLEAN;
1067                retval.u.v_boolean = !qexp_constant_bool (&v1);
1068                break;
1069        case OP_NEGATE:
1070                if (v1.type != CONST_NUMBER)
1071                        retval.value_known = FALSE;
1072                else {
1073                        retval.type = CONST_NUMBER;
1074                        retval.u.v_number = -(v1.u.v_number);
1075                }
1076                break;
1077        }
1078
1079        qexp_constant_unuse (v1);
1080
1081        return retval;
1082}
1083
1084/********** constants ************/
1085static QueryExprConst
1086qexp_evaluate_constant (Bonobo_ServerInfo * si, QueryExpr * e,
1087                        QueryContext * qctx)
1088{
1089        return e->u.constant_value;
1090}
1091
1092/***** The grand poobah of functions *****/
1093QueryExprConst
1094qexp_evaluate (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1095{
1096        QueryExprConst retval;
1097
1098        if (e->have_cached_value) {
1099                retval = e->cached_value;
1100        } else {
1101                switch (e->type) {
1102                case EXPR_FUNCTION:
1103                        retval = qexp_evaluate_function (si, e, qctx);
1104                        break;
1105                case EXPR_VARIABLE:
1106                        retval = qexp_evaluate_variable (si, e, qctx);
1107                        break;
1108                case EXPR_ID:
1109                        retval = qexp_evaluate_id (si, e, qctx);
1110                        break;
1111                case EXPR_BINOP:
1112                        retval = qexp_evaluate_binop (si, e, qctx);
1113                        break;
1114                case EXPR_UNOP:
1115                        retval = qexp_evaluate_unop (si, e, qctx);
1116                        break;
1117                case EXPR_CONSTANT:
1118                        retval = qexp_evaluate_constant (si, e, qctx);
1119                        break;
1120                }
1121        }
1122
1123        if (!e->has_fields) {
1124                e->cached_value = retval;
1125                e->have_cached_value = TRUE;
1126                retval.needs_free = FALSE;      /* We don't want people freeing our cached value... */
1127        }
1128
1129        return retval;
1130}
1131
1132gboolean
1133qexp_matches (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1134{
1135        QueryExprConst res;
1136        gboolean retval;
1137
1138        res = qexp_evaluate (si, e, qctx);
1139
1140        retval = qexp_constant_bool (&res);
1141
1142        qexp_constant_unuse (res);
1143
1144        return retval;
1145}
1146
1147typedef struct
1148{
1149        QueryExpr **sexps;
1150        int nexps;
1151        QueryContext *qctx;
1152}
1153QexpSortData;
1154
1155
1156static int
1157qexp_sort_compare (gconstpointer a, gconstpointer b, gpointer user_data)
1158{
1159        Bonobo_ServerInfo *x = * (Bonobo_ServerInfo **) a;
1160        Bonobo_ServerInfo *y = * (Bonobo_ServerInfo **) b;
1161        QexpSortData * sort_data = user_data;
1162        int i;
1163
1164        if (x == NULL) {
1165                return 1;
1166        }
1167
1168        if (y == NULL) {
1169                return -1;
1170        }
1171
1172        for (i = 0; i < sort_data->nexps; i++) {
1173                QueryExprConst cx, cy;
1174                int res;
1175
1176                cx = qexp_evaluate (x, sort_data->sexps[i], sort_data->qctx);
1177                cy = qexp_evaluate (y, sort_data->sexps[i], sort_data->qctx);
1178
1179                res = qexp_constant_compare (&cx, &cy);
1180
1181                qexp_constant_unuse (cx);
1182                qexp_constant_unuse (cy);
1183
1184                if (res > 0)
1185                        return 1;
1186                else if (res < 0)
1187                        return -1;
1188        }
1189
1190        return 0;
1191}
1192
1193void
1194qexp_sort (Bonobo_ServerInfo ** servers, int nservers, QueryExpr ** sexps,
1195           int nexps, QueryContext * qctx)
1196{
1197        QexpSortData sort_data;
1198
1199        sort_data.sexps = sexps;
1200        sort_data.nexps = nexps;
1201        sort_data.qctx = qctx;
1202
1203        g_qsort_with_data (servers, nservers, sizeof (Bonobo_ServerInfo *),
1204                           qexp_sort_compare, &sort_data);
1205}
Note: See TracBrowser for help on using the repository browser.