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

Revision 18563, 25.7 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18562, which included commits to RCS files with non-trunk default branches.
RevLine 
[18310]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 {
857                        int i;
858                        for (i = 0; i < si->props._length; i++) {
859                                if (!strcmp
860                                    (e->u.id_value,
861                                     si->props._buffer[i].name)) break;
862                        }
863
864                        retval.value_known = FALSE;
865
866                        if (i < si->props._length) {
867                                Bonobo_ActivationPropertyValue *av;
868
869                                av = &si->props._buffer[i].v;
870
871                                switch (av->_d) {
872                                case Bonobo_ACTIVATION_P_STRING:
873                                        retval.type = CONST_STRING;
874                                        retval.u.v_string =
875                                                av->_u.value_string;
876                                        break;
877                                case Bonobo_ACTIVATION_P_NUMBER:
878                                        retval.type = CONST_NUMBER;
879                                        retval.u.v_number =
880                                                av->_u.value_number;
881                                        break;
882                                case Bonobo_ACTIVATION_P_BOOLEAN:
883                                        retval.type = CONST_BOOLEAN;
884                                        retval.u.v_boolean =
885                                                av->_u.value_boolean;
886                                        break;
887                                case Bonobo_ACTIVATION_P_STRINGV:
888                                        {
889                                                /* FIXME bugzilla.eazel.com 2729: it would be nice to replace the
890                                                 * NULL-terminated string arrays with
891                                                 * CORBA_sequence_string all over
892                                                 */
893
894                                                int i;
895                                                retval.type = CONST_STRINGV;
896
897                                                retval.needs_free = TRUE;
898
899                                                retval.u.v_stringv =
900                                                        g_malloc (sizeof
901                                                                  (char *) *
902                                                                  (av->
903                                                                   _u.value_stringv._length
904                                                                   + 1));
905                                                for (i = 0;
906                                                     i <
907                                                     av->_u.
908                                                     value_stringv._length;
909                                                     i++) retval.
910                                                                u.v_stringv[i]
911                                                                =
912                                                                g_strdup
913                                                                (av->_u.value_stringv._buffer
914                                                                 [i]);
915                                                retval.u.v_stringv[i] = NULL;
916                                        }
917                                        break;
918                                }
919
920                                retval.value_known = TRUE;
921                        } else if (qctx->id_evaluator)
922                                retval =
923                                        qctx->id_evaluator (si, e->u.id_value,
924                                                            qctx);
925                }
926        }
927
928        return retval;
929}
930
931/********* binary operators *********/
932
933static QueryExprConst
934qexp_evaluate_binop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
935{
936        QueryExprConst retval, v1, v2;
937        gboolean negate_result = FALSE;
938
939        v2.value_known = FALSE; /* To make sure that qexp_constant_unuse works properly if we short-circuit */
940
941        retval.value_known = TRUE;
942        retval.needs_free = FALSE;
943
944        v1 = qexp_evaluate (si, e->u.binop_value.op1, qctx);
945
946        /* Perform short-circuiting */
947        switch (e->u.binop_value.type) {
948        case OP_OR:
949                if (v1.value_known && qexp_constant_bool (&v1)) {
950                        retval.type = CONST_BOOLEAN;
951                        retval.u.v_boolean = TRUE;
952                        qexp_constant_unuse (v1);
953                        return retval;
954                }
955                break;
956        case OP_AND:
957                if (v1.value_known && !qexp_constant_bool (&v1)) {
958                        retval.type = CONST_BOOLEAN;
959                        retval.u.v_boolean = FALSE;
960                        qexp_constant_unuse (v1);
961                        return retval;
962                }
963                break;
964        default:
965                break;
966        }
967
968        v2 = qexp_evaluate (si, e->u.binop_value.op2, qctx);
969
970        retval.value_known = TRUE;
971
972        switch (e->u.binop_value.type) {
973        case OP_NEQ:
974                negate_result = TRUE;
975        case OP_EQ:
976                retval.type = CONST_BOOLEAN;
977                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) == 0;
978                break;
979        case OP_GEQ:
980                negate_result = TRUE;
981        case OP_LT:
982                retval.type = CONST_BOOLEAN;
983                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) < 0;
984                break;
985        case OP_LEQ:
986                negate_result = TRUE;
987        case OP_GT:
988                retval.type = CONST_BOOLEAN;
989                retval.u.v_boolean = qexp_constant_compare (&v1, &v2) > 0;
990                break;
991        case OP_OR:
992                retval.type = CONST_BOOLEAN;
993                retval.u.v_boolean = qexp_constant_bool (&v1)
994                        || qexp_constant_bool (&v2);
995                break;
996        case OP_AND:
997                retval.type = CONST_BOOLEAN;
998                retval.u.v_boolean = qexp_constant_bool (&v1)
999                        && qexp_constant_bool (&v2);
1000                break;
1001        case OP_MULTIPLY:
1002                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1003                        retval.value_known = FALSE;
1004                else {
1005                        retval.type = CONST_NUMBER;
1006                        retval.u.v_number = v1.u.v_number * v2.u.v_number;
1007                }
1008                break;
1009        case OP_DIVIDE:
1010                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1011                        retval.value_known = FALSE;
1012                else {
1013                        retval.type = CONST_NUMBER;
1014                        if (v2.u.v_number == 0.0)
1015                                retval.value_known = FALSE;
1016                        else
1017                                retval.u.v_number =
1018                                        v1.u.v_number / v2.u.v_number;
1019                }
1020                break;
1021        case OP_ADD:
1022                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1023                        retval.value_known = FALSE;
1024                else {
1025                        retval.type = CONST_NUMBER;
1026                        retval.u.v_number = v1.u.v_number + v2.u.v_number;
1027                }
1028                break;
1029        case OP_SUBTRACT:
1030                if (v1.type != CONST_NUMBER || v2.type != CONST_NUMBER)
1031                        retval.value_known = FALSE;
1032                else {
1033                        retval.type = CONST_NUMBER;
1034                        retval.u.v_number = v1.u.v_number - v2.u.v_number;
1035                }
1036                break;
1037        case OP_XOR:
1038                retval.type = CONST_BOOLEAN;
1039                retval.u.v_boolean =
1040                        qexp_constant_bool (&v1) ^ qexp_constant_bool (&v2);
1041                break;
1042        }
1043
1044        if (negate_result)
1045                retval.u.v_boolean = !retval.u.v_boolean;
1046
1047        qexp_constant_unuse (v1);
1048        qexp_constant_unuse (v2);
1049
1050        return retval;
1051}
1052
1053/********** unary operators **********/
1054static QueryExprConst
1055qexp_evaluate_unop (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1056{
1057        QueryExprConst retval, v1;
1058
1059        retval.value_known = TRUE;
1060
1061        v1 = qexp_evaluate (si, e->u.unop_value.op, qctx);
1062        switch (e->u.unop_value.type) {
1063        case OP_NOT:
1064                retval.type = CONST_BOOLEAN;
1065                retval.u.v_boolean = !qexp_constant_bool (&v1);
1066                break;
1067        case OP_NEGATE:
1068                if (v1.type != CONST_NUMBER)
1069                        retval.value_known = FALSE;
1070                else {
1071                        retval.type = CONST_NUMBER;
1072                        retval.u.v_number = -(v1.u.v_number);
1073                }
1074                break;
1075        }
1076
1077        qexp_constant_unuse (v1);
1078
1079        return retval;
1080}
1081
1082/********** constants ************/
1083static QueryExprConst
1084qexp_evaluate_constant (Bonobo_ServerInfo * si, QueryExpr * e,
1085                        QueryContext * qctx)
1086{
1087        return e->u.constant_value;
1088}
1089
1090/***** The grand poobah of functions *****/
1091QueryExprConst
1092qexp_evaluate (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1093{
1094        QueryExprConst retval;
1095
1096        if (e->have_cached_value) {
1097                retval = e->cached_value;
1098        } else {
1099                switch (e->type) {
1100                case EXPR_FUNCTION:
1101                        retval = qexp_evaluate_function (si, e, qctx);
1102                        break;
1103                case EXPR_VARIABLE:
1104                        retval = qexp_evaluate_variable (si, e, qctx);
1105                        break;
1106                case EXPR_ID:
1107                        retval = qexp_evaluate_id (si, e, qctx);
1108                        break;
1109                case EXPR_BINOP:
1110                        retval = qexp_evaluate_binop (si, e, qctx);
1111                        break;
1112                case EXPR_UNOP:
1113                        retval = qexp_evaluate_unop (si, e, qctx);
1114                        break;
1115                case EXPR_CONSTANT:
1116                        retval = qexp_evaluate_constant (si, e, qctx);
1117                        break;
1118                }
1119        }
1120
1121        if (!e->has_fields) {
1122                e->cached_value = retval;
1123                e->have_cached_value = TRUE;
1124                retval.needs_free = FALSE;      /* We don't want people freeing our cached value... */
1125        }
1126
1127        return retval;
1128}
1129
1130gboolean
1131qexp_matches (Bonobo_ServerInfo * si, QueryExpr * e, QueryContext * qctx)
1132{
1133        QueryExprConst res;
1134        gboolean retval;
1135
1136        res = qexp_evaluate (si, e, qctx);
1137
1138        retval = qexp_constant_bool (&res);
1139
1140        qexp_constant_unuse (res);
1141
1142        return retval;
1143}
1144
1145typedef struct
1146{
1147        QueryExpr **sexps;
1148        int nexps;
1149        QueryContext *qctx;
1150}
1151QexpSortData;
1152
1153
1154static int
1155qexp_sort_compare (gconstpointer a, gconstpointer b, gpointer user_data)
1156{
1157        Bonobo_ServerInfo *x = * (Bonobo_ServerInfo **) a;
1158        Bonobo_ServerInfo *y = * (Bonobo_ServerInfo **) b;
1159        QexpSortData * sort_data = user_data;
1160        int i;
1161
1162        if (x == NULL) {
1163                return 1;
1164        }
1165
1166        if (y == NULL) {
1167                return -1;
1168        }
1169
1170        for (i = 0; i < sort_data->nexps; i++) {
1171                QueryExprConst cx, cy;
1172                int res;
1173
1174                cx = qexp_evaluate (x, sort_data->sexps[i], sort_data->qctx);
1175                cy = qexp_evaluate (y, sort_data->sexps[i], sort_data->qctx);
1176
1177                res = qexp_constant_compare (&cx, &cy);
1178
1179                qexp_constant_unuse (cx);
1180                qexp_constant_unuse (cy);
1181
1182                if (res > 0)
1183                        return 1;
1184                else if (res < 0)
1185                        return -1;
1186        }
1187
1188        return 0;
1189}
1190
1191void
1192qexp_sort (Bonobo_ServerInfo ** servers, int nservers, QueryExpr ** sexps,
1193           int nexps, QueryContext * qctx)
1194{
1195        QexpSortData sort_data;
1196
1197        sort_data.sexps = sexps;
1198        sort_data.nexps = nexps;
1199        sort_data.qctx = qctx;
1200
1201        g_qsort_with_data (servers, nservers, sizeof (Bonobo_ServerInfo *),
1202                           qexp_sort_compare, &sort_data);
1203}
Note: See TracBrowser for help on using the repository browser.