a81d396fb95b1fd4a3c77ffaaeeaabc65b960973
[obnox/wireshark/wip.git] / dfilter.c
1 /* dfilter.c
2  * Routines for display filters
3  *
4  * $Id: dfilter.c,v 1.14 1999/08/20 21:19:28 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  * Copyright 1998 Gerald Combs
9  *
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #ifdef HAVE_SYS_TYPES_H
31 # include <sys/types.h>
32 #endif
33
34 #ifndef _STDIO_H
35 #include <stdio.h>
36 #endif
37
38 #ifndef _STRING_H
39 #include <string.h>
40 #endif
41
42 #ifdef NEED_SNPRINTF_H
43 # ifdef HAVE_STDARG_H
44 #  include <stdarg.h>
45 # else
46 #  include <varargs.h>
47 # endif
48 # include "snprintf.h"
49 #endif
50
51 #ifndef __G_LIB_H__
52 #include <glib.h>
53 #endif
54
55 #ifndef __PROTO_H__
56 #include "proto.h"
57 #endif
58
59 #ifndef __DFILTER_H__
60 #include "dfilter.h"
61 #endif
62
63 #ifndef __UTIL_H__
64 #include "util.h"
65 #endif
66
67 #include "dfilter-int.h"
68 #include "dfilter-grammar.h"
69
70 int dfilter_parse(void); /* yacc entry-point */
71
72 #define DFILTER_LEX_ABBREV_OFFSET       2000
73
74 /* Balanced tree of abbreviations and IDs */
75 GTree *dfilter_tokens = NULL;
76
77 /* Comparision function for tree insertion. A wrapper around strcmp() */
78 static int g_strcmp(gconstpointer a, gconstpointer b);
79
80 /* Silly global variables used to pass parameter to check_relation_bytes() */
81 int bytes_offset = 0;
82 int bytes_length = 0;
83
84 YYSTYPE yylval;
85
86 /* Global error message space for dfilter_compile errors */
87 gchar dfilter_error_msg_buf[1024];
88 gchar *dfilter_error_msg;       /* NULL when no error resulted */
89
90 static gboolean dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8 *pd);
91 static gboolean check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
92 static gboolean check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd);
93 static GArray* get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd);
94 static GArray* get_values_from_dfilter(dfilter_node *dnode, GNode *gnode);
95 static gboolean check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree);
96 static void clear_byte_array(gpointer data, gpointer user_data);
97
98 /* this is not so pretty. I need my own g_array "function" (macro) to
99  * retreive the pointer to the data stored in an array cell. I need this
100  * for type ether.. GArray makes it easy for me to store 6 bytes inside an array
101  * cell, but hard to retrieve it.
102  */
103 #define g_array_index_ptr(a,s,i)      (((guint8*) (a)->data) + (i*s))
104
105 void
106 dfilter_init(void)
107 {
108         int i, num_symbols, symbol;
109         char *s;
110
111         dfilter_tokens = g_tree_new(g_strcmp);
112
113         /* Add the header field and protocol abbrevs to the symbol table */
114         num_symbols = proto_registrar_n();
115         for (i=0; i < num_symbols; i++) {
116                 s = proto_registrar_get_abbrev(i);
117                 if (s) {
118                         symbol = DFILTER_LEX_ABBREV_OFFSET + i;
119                         g_tree_insert(dfilter_tokens, s, GINT_TO_POINTER(symbol));
120                 }
121         }
122 }
123 /* XXX - I should eventually g_tree_destroy(dfilter_tokens), when ethereal shuts down */
124
125 /* Compiles the textual representation of the display filter into a tree
126  * of operations to perform. Can be called multiple times, compiling a new
127  * display filter each time, without having to clear any memory used, since
128  * dfilter_compile will take care of that automatically.
129  * 
130  * Returns 0 on success, non-zero on failure.
131  * If a failure, dfilter_error_msg points to an appropriate error message.
132  * This error message is a global string, so another invocation of
133  * dfilter_compile will clear it. If the caller needs is stored, he
134  * needs to g_strdup it himself.
135  */
136 int
137 dfilter_compile(dfilter *df, gchar *dfilter_text)
138 {
139         int retval;
140
141         g_assert(dfilter_text != NULL);
142
143         dfilter_clear_filter(df);
144         df->dftext = g_strdup(dfilter_text);
145
146         /* tell the scanner to use this string as input */
147         dfilter_scanner_text(df->dftext);
148
149         /* Assign global variable so yyparse knows which dfilter we're talking about */
150         global_df = df;
151         dfilter_error_msg = NULL;
152
153         /* The magic happens right here. */
154         retval = dfilter_parse();
155
156         /* clean up lex */
157         dfilter_scanner_cleanup();
158
159         /* If a parse error occurred, fill in a generic error message
160          * if one was not created during parsing. */
161         if (retval != 0) {
162                 if (dfilter_error_msg == NULL) {
163                         dfilter_error_msg = &dfilter_error_msg_buf[0];
164                         snprintf(dfilter_error_msg, sizeof(dfilter_error_msg_buf),
165                                 "Unable to parse filter string \"%s\".",
166                                 dfilter_text);
167                 }
168         }
169
170         return retval;
171 }
172
173 /* clear the current filter, w/o clearing memchunk area which is where we'll
174  * put new nodes in a future filter */
175 void
176 dfilter_clear_filter(dfilter *df)
177 {
178         if (!df)
179                 return;
180
181         if (df->dftext)
182                 g_free(df->dftext);
183
184         if (df->dftree != NULL)
185                 g_node_destroy(df->dftree);
186
187         /* clear the memory that the tree was using for nodes */
188         if (df->node_memchunk)
189                 g_mem_chunk_reset(df->node_memchunk);
190
191         /* clear the memory that the tree was using for byte arrays */
192         if (df->list_of_byte_arrays) {
193                 g_slist_foreach(df->list_of_byte_arrays, clear_byte_array, NULL);
194                 g_slist_free(df->list_of_byte_arrays);
195         }
196
197         df->dftext = NULL;
198         df->dftree = NULL;
199         df->list_of_byte_arrays = NULL;
200 }
201
202 /* Allocates new dfilter, initializes values, and returns pointer to dfilter */
203 dfilter*
204 dfilter_new(void)
205 {
206         dfilter *df;
207
208         df = g_malloc(sizeof(dfilter));
209
210         df->dftext = NULL;
211         df->dftree = NULL;
212         df->node_memchunk = g_mem_chunk_new("df->node_memchunk",
213                 sizeof(dfilter_node), 20 * sizeof(dfilter_node), G_ALLOC_ONLY);
214         df->list_of_byte_arrays = NULL;
215
216         return df;
217 }
218
219 /* Frees all memory used by dfilter, and frees dfilter itself */
220 void
221 dfilter_destroy(dfilter *df)
222 {
223         if (!df)
224                 return;
225
226         dfilter_clear_filter(df);
227
228         /* Git rid of memchunk */
229         if (df->node_memchunk)
230                 g_mem_chunk_destroy(df->node_memchunk);
231
232         g_free(df);
233 }
234
235
236
237
238
239 static void
240 clear_byte_array(gpointer data, gpointer user_data)
241 {
242         GByteArray *barray = data;
243         if (barray)
244                 g_byte_array_free(barray, TRUE);
245 }
246
247 void
248 dfilter_error(char *s)
249 {
250 /*      fprintf(stderr, "%s\n", s);
251         Do not report the error, just let yyparse() return 1 */
252 }
253
254 void
255 dfilter_yyerror(char *fmt, ...)
256 {
257         /* XXX - is this cool? check for mem leak */
258         global_df->dftree = NULL;
259         dfilter_error(fmt);
260 }
261
262 /* lookup an abbreviation in our token tree, returing the ID #
263  * If the abbreviation doesn't exit, returns 0 */
264 int dfilter_lookup_token(char *abbrev)
265 {
266         int value;
267
268         g_assert(abbrev != NULL);
269         value =  GPOINTER_TO_INT(g_tree_lookup(dfilter_tokens, abbrev));
270
271         if (value < DFILTER_LEX_ABBREV_OFFSET) {
272                 return 0;
273         }
274         return value - DFILTER_LEX_ABBREV_OFFSET;
275 }
276
277 static int
278 g_strcmp(gconstpointer a, gconstpointer b)
279 {
280         return strcmp((const char*)a, (const char*)b);
281 }
282
283
284 gboolean
285 dfilter_apply(dfilter *dfcode, proto_tree *ptree, const guint8* pd)
286 {
287         gboolean retval;
288         retval = dfilter_apply_node(dfcode->dftree, ptree, pd);
289         return retval;
290 }
291
292 static gboolean
293 dfilter_apply_node(GNode *gnode, proto_tree *ptree, const guint8* pd)
294 {
295         GNode           *gnode_a, *gnode_b;
296         dfilter_node    *dnode = (dfilter_node*) (gnode->data);
297
298         /* We'll get 2 NULLs if we don't have children */
299         gnode_a = g_node_nth_child(gnode, 0);
300         gnode_b = g_node_nth_child(gnode, 1);
301
302         switch(dnode->ntype) {
303         case variable:
304                 /* We'll never see this case because if the parser finds the name of
305                  * a variable, it will cause it to be an 'existence' operation.
306                  */
307                 g_assert_not_reached();
308
309         case logical:
310                 return check_logical(dnode->value.logical, gnode_a, gnode_b, ptree, pd);
311
312         case relation:
313                 g_assert(gnode_a && gnode_b);
314                 return check_relation(dnode->value.relation, gnode_a, gnode_b, ptree, pd);
315
316         case alternation:
317                 g_assert_not_reached();
318                 /* not coded yet */
319         
320         case numeric:
321         case ipv4:
322         case boolean:
323         case ether:
324         case string:
325         case abs_time:
326         case bytes:
327         case ipxnet:
328                 /* the only time we'll see these at this point is if the display filter
329                  * is really wacky. (like simply "192.168.1.1"). The parser as it stands
330                  * now let these by. Just return TRUE */
331                 g_assert(!gnode_a && !gnode_b);
332                 return TRUE;
333
334         case existence: /* checking the existence of a protocol or hf*/
335                 g_assert(!gnode_a && !gnode_b);
336                 return check_existence_in_ptree(dnode, ptree);
337         }
338
339         g_assert_not_reached();
340         return FALSE;
341 }
342
343 static gboolean
344 check_logical(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8 *pd)
345 {
346         gboolean val_a = dfilter_apply_node(a, ptree, pd);
347         gboolean val_b;
348
349         switch(operand) {
350         case TOK_AND:
351                 return (val_a && dfilter_apply_node(b, ptree, pd));
352         case TOK_OR:
353                 return (val_a || dfilter_apply_node(b, ptree, pd));
354         case TOK_XOR:
355                 val_b = dfilter_apply_node(b, ptree, pd);
356                 return ( ( val_a || val_b ) && ! ( val_a && val_b ) );
357         case TOK_NOT:
358                 return (!val_a);
359         default:
360                 g_assert_not_reached();
361         }       
362         g_assert_not_reached();
363         return FALSE;
364 }
365
366 /* this is inefficient. I get arrays for both a and b that represent all the values present. That is,
367  * if a is bootp.option, e.g., i'll get an array showing all the bootp.option values in the protocol
368  * tree. Then I'll get an array for b, which more than likely is a single int, and then I'll compare
369  * them all. It makes my coding easier in the beginning, but I should change this to make it run
370  * faster.
371  */
372 static gboolean
373 check_relation(gint operand, GNode *a, GNode *b, proto_tree *ptree, const guint8* pd)
374 {
375         dfilter_node    *node_a = (dfilter_node*) (a->data);
376         dfilter_node    *node_b = (dfilter_node*) (b->data);
377         GArray          *vals_a, *vals_b;
378         gboolean        retval;
379
380
381         bytes_length = MIN(node_a->length, node_b->length);
382         bytes_offset = MIN(node_a->offset, node_b->offset);
383         if (node_a->ntype == variable)
384                 vals_a = get_values_from_ptree(node_a, ptree, pd);
385         else
386                 vals_a = get_values_from_dfilter(node_a, a);
387
388         if (node_b->ntype == variable)
389                 vals_b = get_values_from_ptree(node_b, ptree, pd);
390         else
391                 vals_b = get_values_from_dfilter(node_b, b);
392
393         retval =  node_a->check_relation_func(operand, vals_a, vals_b);
394
395         g_array_free(vals_a, FALSE);
396         g_array_free(vals_b, FALSE);
397
398         return retval;
399 }
400
401 static gboolean
402 check_existence_in_ptree(dfilter_node *dnode, proto_tree *ptree)
403 {
404         int             target_field;
405         proto_tree      *subtree;
406
407         target_field = dnode->value.variable;
408         subtree = proto_find_field(ptree, target_field);
409
410         if (subtree)
411                 return TRUE;
412         else
413                 return FALSE;
414 }
415
416 static GArray*
417 get_values_from_ptree(dfilter_node *dnode, proto_tree *ptree, const guint8 *pd)
418 {
419         GArray          *array;
420         int             parent_protocol;
421         int             target_field;
422         proto_tree      *subtree = NULL; /* where the parent protocol's sub-tree starts */
423         proto_tree_search_info sinfo;
424
425         g_assert(dnode->elem_size > 0);
426         array = g_array_new(FALSE, FALSE, dnode->elem_size);
427
428         target_field = dnode->value.variable;
429
430         /* Find the proto_tree subtree where we should start searching.*/
431         if (proto_registrar_is_protocol(target_field)) {
432                 subtree = proto_find_protocol(ptree, target_field);
433         }
434         else {
435                 parent_protocol = proto_registrar_get_parent(target_field);
436                 if (parent_protocol >= 0) {
437                         subtree = proto_find_protocol(ptree, parent_protocol);
438                 }
439         }
440
441         if (subtree) {
442                 sinfo.target_field = target_field;
443                 sinfo.result_array = array;
444                 sinfo.packet_data = pd;
445                 proto_get_field_values(subtree, dnode->fill_array_func, &sinfo);
446         }
447
448         return array;
449 }
450
451 static GArray*
452 get_values_from_dfilter(dfilter_node *dnode, GNode *gnode)
453 {
454         GArray          *array;
455
456         g_assert(dnode->elem_size > 0);
457         array = g_array_new(FALSE, FALSE, dnode->elem_size);
458
459         g_node_traverse(gnode, G_IN_ORDER, G_TRAVERSE_ALL, -1, dnode->fill_array_func, array);
460 /*      dnode->fill_array_func(gnode, array);*/
461         return array;
462 }
463
464 gboolean fill_array_numeric_variable(GNode *gnode, gpointer data)
465 {
466         proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
467         field_info              *fi = (field_info*) (gnode->data);
468
469         if (fi->hfinfo->id == sinfo->target_field) {
470                 g_array_append_val(sinfo->result_array, fi->value.numeric);
471         }
472
473         return FALSE; /* FALSE = do not end traversal of GNode tree */
474 }
475
476 gboolean fill_array_ether_variable(GNode *gnode, gpointer data)
477 {
478         proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
479         field_info              *fi = (field_info*) (gnode->data);
480
481         if (fi->hfinfo->id == sinfo->target_field) {
482                 g_array_append_val(sinfo->result_array, fi->value.ether);
483         }
484
485         return FALSE; /* FALSE = do not end traversal of GNode tree */
486 }
487
488 gboolean fill_array_bytes_variable(GNode *gnode, gpointer data)
489 {
490         proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
491         field_info              *fi = (field_info*) (gnode->data);
492         GByteArray              *barray;
493
494         if (fi->hfinfo->id == sinfo->target_field) {
495                 barray = g_byte_array_new();
496                 /*list_of_byte_arrays = g_slist_append(list_of_byte_arrays, barray);*/
497                 g_byte_array_append(barray, sinfo->packet_data + fi->start + bytes_offset, bytes_length);
498                 g_array_append_val(sinfo->result_array, barray);
499         }
500
501         return FALSE; /* FALSE = do not end traversal of GNode tree */
502 }
503
504 gboolean fill_array_boolean_variable(GNode *gnode, gpointer data)
505 {
506         proto_tree_search_info  *sinfo = (proto_tree_search_info*)data;
507         field_info              *fi = (field_info*) (gnode->data);
508
509         if (fi->hfinfo->id == sinfo->target_field) {
510                 g_array_append_val(sinfo->result_array, fi->value.boolean);
511         }
512
513         return FALSE; /* FALSE = do not end traversal of GNode tree */
514 }
515
516 gboolean fill_array_numeric_value(GNode *gnode, gpointer data)
517 {
518         GArray          *array = (GArray*)data;
519         dfilter_node    *dnode = (dfilter_node*) (gnode->data);
520
521         g_array_append_val(array, dnode->value.numeric);
522
523         return FALSE; /* FALSE = do not end traversal of GNode tree */
524 }
525
526 gboolean fill_array_ether_value(GNode *gnode, gpointer data)
527 {
528         GArray          *array = (GArray*)data;
529         dfilter_node    *dnode = (dfilter_node*) (gnode->data);
530
531         g_array_append_val(array, dnode->value.ether);
532
533         return FALSE; /* FALSE = do not end traversal of GNode tree */
534 }
535
536 gboolean fill_array_bytes_value(GNode *gnode, gpointer data)
537 {
538         GArray          *array = (GArray*)data;
539         dfilter_node    *dnode = (dfilter_node*) (gnode->data);
540         GByteArray      *barray = dnode->value.bytes;
541
542         g_array_append_val(array, barray);
543
544         return FALSE; /* FALSE = do not end traversal of GNode tree */
545 }
546
547 gboolean fill_array_boolean_value(GNode *gnode, gpointer data)
548 {
549         GArray          *array = (GArray*)data;
550         dfilter_node    *dnode = (dfilter_node*) (gnode->data);
551
552         g_array_append_val(array, dnode->value.boolean);
553
554         return FALSE; /* FALSE = do not end traversal of GNode tree */
555 }
556
557
558 gboolean check_relation_numeric(gint operand, GArray *a, GArray *b)
559 {
560         int     i, j, len_a, len_b;
561         guint32 val_a;
562
563         len_a = a->len;
564         len_b = b->len;
565
566
567         switch(operand) {
568         case TOK_EQ:
569                 for(i = 0; i < len_a; i++) {
570                         val_a = g_array_index(a, guint32, i);
571                         for (j = 0; j < len_b; j++) {
572                                 if (val_a == g_array_index(b, guint32, j))
573                                         return TRUE;
574                         }
575                 }
576                 return FALSE;
577
578         case TOK_NE:
579                 for(i = 0; i < len_a; i++) {
580                         val_a = g_array_index(a, guint32, i);
581                         for (j = 0; j < len_b; j++) {
582                                 if (val_a != g_array_index(b, guint32, j))
583                                         return TRUE;
584                         }
585                 }
586                 return FALSE;
587
588         case TOK_GT:
589                 for(i = 0; i < len_a; i++) {
590                         val_a = g_array_index(a, guint32, i);
591                         for (j = 0; j < len_b; j++) {
592                                 if (val_a > g_array_index(b, guint32, j))
593                                         return TRUE;
594                         }
595                 }
596                 return FALSE;
597
598         case TOK_GE:
599                 for(i = 0; i < len_a; i++) {
600                         val_a = g_array_index(a, guint32, i);
601                         for (j = 0; j < len_b; j++) {
602                                 if (val_a >= g_array_index(b, guint32, j))
603                                         return TRUE;
604                         }
605                 }
606                 return FALSE;
607
608         case TOK_LT:
609                 for(i = 0; i < len_a; i++) {
610                         val_a = g_array_index(a, guint32, i);
611                         for (j = 0; j < len_b; j++) {
612                                 if (val_a < g_array_index(b, guint32, j))
613                                         return TRUE;
614                         }
615                 }
616                 return FALSE;
617
618         case TOK_LE:
619                 for(i = 0; i < len_a; i++) {
620                         val_a = g_array_index(a, guint32, i);
621                         for (j = 0; j < len_b; j++) {
622                                 if (val_a <= g_array_index(b, guint32, j))
623                                         return TRUE;
624                         }
625                 }
626                 return FALSE;
627
628         default:
629                 g_assert_not_reached();
630         }
631
632         g_assert_not_reached();
633         return FALSE;
634 }
635
636
637 gboolean check_relation_ether(gint operand, GArray *a, GArray *b)
638 {
639         int     i, j, len_a, len_b;
640         guint8  *ptr_a, *ptr_b;
641
642         len_a = a->len;
643         len_b = b->len;
644
645
646         switch(operand) {
647         case TOK_EQ:
648                 for(i = 0; i < len_a; i++) {
649                         ptr_a = g_array_index_ptr(a, 6, i);
650                         for (j = 0; j < len_b; j++) {
651                                 ptr_b = g_array_index_ptr(b, 6, j);
652                                 if (memcmp(ptr_a, ptr_b, 6) == 0)
653                                         return TRUE;
654                         }
655                 }
656                 return FALSE;
657
658         case TOK_NE:
659                 for(i = 0; i < len_a; i++) {
660                         ptr_a = g_array_index_ptr(a, 6, i);
661                         for (j = 0; j < len_b; j++) {
662                                 ptr_b = g_array_index_ptr(b, 6, j);
663                                 if (memcmp(ptr_a, ptr_b, 6) != 0)
664                                         return TRUE;
665                         }
666                 }
667                 return FALSE;
668         }
669
670         g_assert_not_reached();
671         return FALSE;
672 }
673
674 gboolean check_relation_bytes(gint operand, GArray *a, GArray *b)
675 {
676         int     i, j, len_a, len_b;
677         GByteArray      *ptr_a,*ptr_b;
678
679         len_a = a->len;
680         len_b = b->len;
681
682
683         switch(operand) {
684         case TOK_EQ:
685                 for(i = 0; i < len_a; i++) {
686                         ptr_a = g_array_index(a, GByteArray*, i);
687                         for (j = 0; j < len_b; j++) {
688                                 ptr_b = g_array_index(b, GByteArray*, j);
689                                 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) == 0)
690                                         return TRUE;
691                         }
692                 }
693                 return FALSE;
694
695         case TOK_NE:
696                 for(i = 0; i < len_a; i++) {
697                         ptr_a = g_array_index(a, GByteArray*, i);
698                         for (j = 0; j < len_b; j++) {
699                                 ptr_b = g_array_index(b, GByteArray*, j);
700                                 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) != 0)
701                                         return TRUE;
702                         }
703                 }
704                 return FALSE;
705
706         case TOK_GT:
707                 for(i = 0; i < len_a; i++) {
708                         ptr_a = g_array_index(a, GByteArray*, i);
709                         for (j = 0; j < len_b; j++) {
710                                 ptr_b = g_array_index(b, GByteArray*, j);
711                                 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) > 0)
712                                         return TRUE;
713                         }
714                 }
715                 return FALSE;
716
717         case TOK_LT:
718                 for(i = 0; i < len_a; i++) {
719                         ptr_a = g_array_index(a, GByteArray*, i);
720                         for (j = 0; j < len_b; j++) {
721                                 ptr_b = g_array_index(b, GByteArray*, j);
722                                 if (memcmp(ptr_a->data, ptr_b->data, bytes_length) < 0)
723                                         return TRUE;
724                         }
725                 }
726                 return FALSE;
727         }
728
729         g_assert_not_reached();
730         return FALSE;
731 }
732
733 gboolean check_relation_boolean(gint operand, GArray *a, GArray *b)
734 {
735         int     i, j, len_a, len_b;
736         guint32 val_a;
737
738         len_a = a->len;
739         len_b = b->len;
740
741
742         switch(operand) {
743         case TOK_EQ:
744                 for(i = 0; i < len_a; i++) {
745                         val_a = g_array_index(a, guint32, i);
746                         for (j = 0; j < len_b; j++) {
747                                 if (val_a == g_array_index(b, guint32, j))
748                                         return TRUE;
749                         }
750                 }
751                 return FALSE;
752
753         case TOK_NE:
754                 for(i = 0; i < len_a; i++) {
755                         val_a = g_array_index(a, guint32, i);
756                         for (j = 0; j < len_b; j++) {
757                                 if (val_a != g_array_index(b, guint32, j))
758                                         return TRUE;
759                         }
760                 }
761                 return FALSE;
762
763         default:
764                 g_assert_not_reached();
765         }
766
767         g_assert_not_reached();
768         return FALSE;
769 }
770