2
* @file libgeis/geis_filter.c
3
* @brief implementation of the GEIS v2.0 API filter module
5
* Copyright 2010, 2011 Canonical Ltd.
7
* This library is free software; you can redistribute it and/or modify it under
8
* the terms of the GNU Lesser General Public License as published by the Free
9
* Software Foundation; either version 3 of the License, or (at your option) any
12
* This library is distributed in the hope that it will be useful, but WITHOUT
13
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17
* You should have received a copy of the GNU Lesser General Public License
18
* along with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21
#include "geis_config.h"
22
#include "geis_filter.h"
24
#include "geis_atomic.h"
25
#include "geis_attr.h"
26
#include "geis_error.h"
27
#include "geis_filter_term.h"
28
#include "geis_logging.h"
29
#include "geis_private.h"
37
GeisRefCount refcount;
41
GeisBackendToken backend_token;
42
GeisFilterTermBag terms;
47
GeisFilter *filter_store;
48
GeisSize filter_store_size;
49
GeisSize filter_count;
52
static const int filter_bag_growth_constant = 2;
54
static GeisSize s_filter_oid = 0;
58
* Creates a new filter bag,
63
GeisFilterBag bag = calloc(1, sizeof(struct _GeisFilterBag));
66
geis_error("failed to allocate filter bag");
70
bag->filter_store_size = 3;
71
bag->filter_count = 0;
72
bag->filter_store = calloc(bag->filter_store_size, sizeof(GeisFilter));
73
if (!bag->filter_store)
75
geis_error("failed to allocate filter bag store");
88
* Destroys a filter bag.
91
geis_filter_bag_delete(GeisFilterBag bag)
94
for (i = bag->filter_count; i > 0; --i)
96
geis_filter_delete(bag->filter_store[i-1]);
98
free(bag->filter_store);
104
* Gets the number of filters in the bag.
107
geis_filter_bag_count(GeisFilterBag bag)
109
return bag->filter_count;
114
* Gets an indicated filter from a bag.
117
geis_filter_bag_filter(GeisFilterBag bag, GeisSize index)
119
GeisFilter filter = NULL;
120
if (index < bag->filter_count)
122
filter = bag->filter_store[index];
129
* Gets an indicated filter from a bag.
132
geis_filter_bag_filter_by_name(GeisFilterBag bag, GeisString name)
134
GeisFilter filter = NULL;
136
for (i = 0; i < bag->filter_count; ++i)
138
if (0 == strcmp(bag->filter_store[i]->name, name))
140
filter = bag->filter_store[i];
149
* Gets an iterator initialized to the first filter contained in the bag.
152
geis_filter_bag_begin(GeisFilterBag bag)
154
if (bag->filter_count > 0)
155
return (GeisFilterIterator)bag->filter_store;
156
return geis_filter_bag_end(bag);
161
* * Gets an iterator initialized to one-past-the-end of the filter bag.
164
geis_filter_bag_end(GeisFilterBag bag GEIS_UNUSED)
171
* Advances the iterator to the next filter in the bag.
174
geis_filter_iterator_next(GeisFilterBag bag, GeisFilterIterator iter)
176
GeisFilterIterator new_iter = iter + 1;
177
if ((GeisSize)(new_iter - bag->filter_store) < bag->filter_count)
179
return geis_filter_bag_end(bag);
184
* Inserts a filter in the bag.
187
geis_filter_bag_insert(GeisFilterBag bag, GeisFilter filter)
189
GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
190
if (bag->filter_count >= bag->filter_store_size)
192
GeisSize new_store_size = bag->filter_store_size * filter_bag_growth_constant;
193
GeisFilter *new_store = realloc(bag->filter_store,
194
new_store_size * sizeof(struct _GeisFilter));
197
geis_error("failed to reallocate filter bag");
200
bag->filter_store = new_store;
201
bag->filter_store_size = new_store_size;
203
bag->filter_store[bag->filter_count++] = geis_filter_ref(filter);
204
status = GEIS_STATUS_SUCCESS;
208
geis_filter_unref(filter);
215
* Remoes a filter from the bag.
218
geis_filter_bag_remove(GeisFilterBag bag, GeisFilter filter)
221
GeisStatus status = GEIS_STATUS_SUCCESS;
222
for (i = 0; i < bag->filter_count; ++i)
224
if (bag->filter_store[i] == filter)
227
geis_filter_delete(bag->filter_store[i]);
229
for (j = i; j < bag->filter_count; ++j)
231
bag->filter_store[j] = bag->filter_store[j+1];
241
* Creates a new, empty filter object.
244
_filter_new_empty(GeisString name)
246
GeisFilter filter = calloc(1, sizeof(struct _GeisFilter));
249
geis_error("error allocating filter");
255
filter->name = strdup(name);
259
filter->name = strdup("");
263
geis_error("error allocating filter name");
266
filter->oid = s_filter_oid++;
278
* Creates a GEIS v2.0 filter object.
281
geis_filter_new(Geis geis, GeisString name)
283
GeisFilter filter = _filter_new_empty(name);
286
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
290
filter->terms = geis_filter_term_bag_new(0);
293
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
294
geis_error("error allocating filter terms");
298
filter->backend_token = geis_backend_token_new(geis,
299
GEIS_BACKEND_TOKEN_INIT_ALL);
300
if (!filter->backend_token)
302
geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
303
geis_error("error allocating filter token");
304
goto unwind_term_bag;
307
filter->geis = geis_ref(geis);
308
geis_filter_ref(filter);
312
geis_filter_term_bag_delete(filter->terms);
314
free((char *)filter->name);
323
* Creates a new filter by copying an existing filter.
326
geis_filter_clone(GeisFilter original, GeisString name)
328
GeisFilter filter = _filter_new_empty(name);
331
geis_error_push(original->geis, GEIS_STATUS_UNKNOWN_ERROR);
335
filter->terms = geis_filter_term_bag_clone(original->terms);
338
geis_error_push(original->geis, GEIS_STATUS_UNKNOWN_ERROR);
339
geis_error("error allocating filter terms");
343
filter->geis = geis_ref(original->geis);
344
filter->backend_token = geis_backend_token_clone(original->backend_token);
345
geis_filter_ref(filter);
349
free((char *)filter->name);
358
* Destroys a GEIS v2.0 filter object.
361
geis_filter_delete(GeisFilter filter)
363
GeisStatus status = GEIS_STATUS_SUCCESS;
365
if (geis_filter_unref(filter) == 0)
367
geis_unref(filter->geis);
368
geis_backend_token_delete(filter->backend_token);
369
geis_filter_term_bag_delete(filter->terms);
370
free((char *)filter->name);
378
* Gets the name given to the filter when it was created.
381
geis_filter_name(GeisFilter filter)
388
* Indicates if the facility is valid.
391
_facility_is_valid(GeisFilterFacility facility)
393
return facility == GEIS_FILTER_DEVICE
394
|| facility == GEIS_FILTER_CLASS
395
|| facility == GEIS_FILTER_REGION
396
|| facility == GEIS_FILTER_SPECIAL;
401
* Indicates if the operation is valid.
404
_operation_is_valid(GeisFilterOperation op)
406
return op == GEIS_FILTER_OP_EQ
407
|| op == GEIS_FILTER_OP_NE
408
|| op == GEIS_FILTER_OP_GT
409
|| op == GEIS_FILTER_OP_GE
410
|| op == GEIS_FILTER_OP_LT
411
|| op == GEIS_FILTER_OP_LE;
416
* Gets the attr description by name.
417
* @todo implement this function
420
_get_attr_type_for_facility(Geis geis,
421
GeisFilterFacility facility,
422
GeisString attr_name)
424
GeisAttrType type = GEIS_ATTR_TYPE_UNKNOWN;
427
case GEIS_FILTER_DEVICE:
428
type = geis_get_device_attr_type(geis, attr_name);
430
case GEIS_FILTER_CLASS:
431
type = geis_get_class_attr_type(geis, attr_name);
433
case GEIS_FILTER_REGION:
434
type = geis_get_region_attr_type(geis, attr_name);
436
case GEIS_FILTER_SPECIAL:
437
type = geis_get_special_attr_type(geis, attr_name);
447
geis_filter_add_term_internal(GeisFilter filter, GeisFilterTerm term)
449
GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
450
GeisAttr attr = geis_filter_term_attr(term);
452
geis_filterable_attribute_foreach(filter->geis,
453
geis_filter_term_facility(term),
454
filter->backend_token,
455
geis_attr_name(attr),
456
geis_filter_term_operation(term),
457
geis_attr_value(attr));
458
geis_filter_term_bag_insert(filter->terms, term);
465
* Adds zero or more terms to a filter.
468
geis_filter_add_term(GeisFilter filter,
469
GeisFilterFacility facility,
472
GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
474
GeisString attr_name;
476
if (!_facility_is_valid(facility))
478
status = GEIS_STATUS_BAD_ARGUMENT;
479
geis_error_push(filter->geis, status);
480
geis_error("invalid filter facility");
484
va_start(varargs, facility);
485
for (attr_name = va_arg(varargs, GeisString);
487
attr_name = va_arg(varargs, GeisString))
489
GeisAttrType attr_type = _get_attr_type_for_facility(filter->geis,
492
if (attr_type == GEIS_ATTR_TYPE_UNKNOWN)
494
status = GEIS_STATUS_BAD_ARGUMENT;
495
geis_error_push(filter->geis, status);
496
geis_error("invalid attr name \"%s\" for facility", attr_name);
500
GeisFilterOperation op = va_arg(varargs, GeisFilterOperation);
501
if (!_operation_is_valid(op))
503
status = GEIS_STATUS_BAD_ARGUMENT;
504
geis_error_push(filter->geis, status);
505
geis_error("invalid filter operation");
511
case GEIS_ATTR_TYPE_BOOLEAN:
513
GeisBoolean value = va_arg(varargs, GeisBoolean);
514
geis_filterable_attribute_foreach(filter->geis,
516
filter->backend_token,
520
GeisAttr attr = geis_attr_new(attr_name, attr_type, &value);
521
GeisFilterTerm term = geis_filter_term_new(facility, op, attr);
522
geis_filter_term_bag_insert(filter->terms, term);
526
case GEIS_ATTR_TYPE_FLOAT:
528
GeisFloat value = va_arg(varargs, double);
529
geis_filterable_attribute_foreach(filter->geis,
531
filter->backend_token,
535
GeisAttr attr = geis_attr_new(attr_name, attr_type, &value);
536
GeisFilterTerm term = geis_filter_term_new(facility, op, attr);
537
geis_filter_term_bag_insert(filter->terms, term);
541
case GEIS_ATTR_TYPE_INTEGER:
543
GeisInteger value = va_arg(varargs, GeisInteger);
544
geis_filterable_attribute_foreach(filter->geis,
546
filter->backend_token,
550
GeisAttr attr = geis_attr_new(attr_name, attr_type, &value);
551
GeisFilterTerm term = geis_filter_term_new(facility, op, attr);
552
geis_filter_term_bag_insert(filter->terms, term);
556
case GEIS_ATTR_TYPE_POINTER:
558
GeisPointer value = va_arg(varargs, GeisPointer);
559
geis_filterable_attribute_foreach(filter->geis,
561
filter->backend_token,
565
GeisAttr attr = geis_attr_new(attr_name, attr_type, value);
566
GeisFilterTerm term = geis_filter_term_new(facility, op, attr);
567
geis_filter_term_bag_insert(filter->terms, term);
571
case GEIS_ATTR_TYPE_STRING:
573
GeisString value = va_arg(varargs, GeisString);
574
geis_filterable_attribute_foreach(filter->geis,
576
filter->backend_token,
580
GeisAttr attr = geis_attr_new(attr_name, attr_type, (void *)value);
581
GeisFilterTerm term = geis_filter_term_new(facility, op, attr);
582
geis_filter_term_bag_insert(filter->terms, term);
587
status = GEIS_STATUS_BAD_ARGUMENT;
588
geis_error_push(filter->geis, status);
589
geis_error("invalid filter argument");
595
status = GEIS_STATUS_SUCCESS;
603
* Atomically increments filter refcount.
606
geis_filter_ref(GeisFilter filter)
608
geis_atomic_ref(&filter->refcount);
614
* Atomically decrements and returns filter refcount.
617
geis_filter_unref(GeisFilter filter)
619
return geis_atomic_unref(&filter->refcount);
624
* Gets the number of terms in the filter.
627
geis_filter_term_count(GeisFilter filter)
629
return geis_filter_term_bag_count(filter->terms);
634
* Gets the indicated term in the filter.
637
geis_filter_term(GeisFilter filter, GeisSize index)
639
return geis_filter_term_bag_term(filter->terms, index);
643
* Gets the back end token from the filter.
646
geis_filter_token(GeisFilter filter)
648
return filter->backend_token;
653
* Performs the filter function on a Geis event.
656
geis_filter_pass_event(GeisFilter filter, GeisEvent event)
658
GeisBoolean pass = GEIS_TRUE;
659
for (GeisSize i = 0; i < geis_filter_term_bag_count(filter->terms); ++i)
661
GeisFilterTerm term = geis_filter_term_bag_term(filter->terms, i);
662
pass &= geis_filter_term_match_event(term, event);