~matttbe/ubuntu/raring/geis/lp1077376

« back to all changes in this revision

Viewing changes to libgeis/geis_filter.c

  • Committer: Package Import Robot
  • Author(s): Chase Douglas
  • Date: 2012-07-30 08:51:42 UTC
  • Revision ID: package-import@ubuntu.com-20120730085142-jrc33ygjvt0ob1wl
Tags: upstream-2.2.11
ImportĀ upstreamĀ versionĀ 2.2.11

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
 * @file libgeis/geis_filter.c
 
3
 * @brief implementation of the GEIS v2.0 API filter module
 
4
 *
 
5
 * Copyright 2010, 2011 Canonical Ltd.
 
6
 *
 
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
 
10
 * later version.
 
11
 *
 
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
 
15
 * details.
 
16
 *
 
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
 
20
 */
 
21
#include "geis_config.h"
 
22
#include "geis_filter.h"
 
23
 
 
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"
 
30
#include <stdarg.h>
 
31
#include <stdlib.h>
 
32
#include <string.h>
 
33
 
 
34
 
 
35
struct _GeisFilter
 
36
{
 
37
  GeisRefCount      refcount;
 
38
  GeisString        name;
 
39
  Geis              geis;
 
40
  GeisSize          oid;
 
41
  GeisBackendToken  backend_token;
 
42
  GeisFilterTermBag terms;
 
43
};
 
44
 
 
45
struct _GeisFilterBag
 
46
{
 
47
  GeisFilter *filter_store;
 
48
  GeisSize    filter_store_size;
 
49
  GeisSize    filter_count;
 
50
};
 
51
 
 
52
static const int filter_bag_growth_constant = 2;
 
53
 
 
54
static GeisSize s_filter_oid = 0;
 
55
 
 
56
 
 
57
/*
 
58
 * Creates a new filter bag,
 
59
 */
 
60
GeisFilterBag
 
61
geis_filter_bag_new()
 
62
{
 
63
  GeisFilterBag bag = calloc(1, sizeof(struct _GeisFilterBag));
 
64
  if (!bag)
 
65
  {
 
66
    geis_error("failed to allocate filter bag");
 
67
    goto final_exit;
 
68
  }
 
69
 
 
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)
 
74
  {
 
75
    geis_error("failed to allocate filter bag store");
 
76
    goto unwind_bag;
 
77
  }
 
78
  goto final_exit;
 
79
 
 
80
unwind_bag:
 
81
  free(bag);
 
82
final_exit:
 
83
  return bag;
 
84
}
 
85
 
 
86
 
 
87
/*
 
88
 * Destroys a filter bag.
 
89
 */
 
90
void
 
91
geis_filter_bag_delete(GeisFilterBag bag)
 
92
{
 
93
  GeisSize i;
 
94
  for (i = bag->filter_count; i > 0; --i)
 
95
  {
 
96
    geis_filter_delete(bag->filter_store[i-1]);
 
97
  }
 
98
  free(bag->filter_store);
 
99
  free(bag);
 
100
}
 
101
 
 
102
 
 
103
/*
 
104
 * Gets the number of filters in the bag.
 
105
 */
 
106
GeisSize
 
107
geis_filter_bag_count(GeisFilterBag bag)
 
108
{
 
109
  return bag->filter_count;
 
110
}
 
111
 
 
112
 
 
113
/*
 
114
 * Gets an indicated filter from a bag.
 
115
 */
 
116
GeisFilter
 
117
geis_filter_bag_filter(GeisFilterBag bag, GeisSize index)
 
118
{
 
119
  GeisFilter filter = NULL;
 
120
  if (index < bag->filter_count)
 
121
  {
 
122
    filter = bag->filter_store[index];
 
123
  }
 
124
  return filter;
 
125
}
 
126
 
 
127
 
 
128
/*
 
129
 * Gets an indicated filter from a bag.
 
130
 */
 
131
GeisFilter
 
132
geis_filter_bag_filter_by_name(GeisFilterBag bag, GeisString name)
 
133
{
 
134
  GeisFilter filter = NULL;
 
135
  GeisSize i;
 
136
  for (i = 0; i < bag->filter_count; ++i)
 
137
  {
 
138
    if (0 == strcmp(bag->filter_store[i]->name, name))
 
139
    {
 
140
      filter = bag->filter_store[i];
 
141
      break;
 
142
    }
 
143
  }
 
144
  return filter;
 
145
}
 
146
      
 
147
 
 
148
/*
 
149
 * Gets an iterator initialized to the first filter contained in the bag.
 
150
 */
 
151
GeisFilterIterator
 
152
geis_filter_bag_begin(GeisFilterBag bag)
 
153
{
 
154
  if (bag->filter_count > 0)
 
155
    return (GeisFilterIterator)bag->filter_store;
 
156
  return geis_filter_bag_end(bag);
 
157
}
 
158
 
 
159
 
 
160
/*
 
161
 * * Gets an iterator initialized to one-past-the-end of the filter bag.
 
162
 */
 
163
GeisFilterIterator
 
164
geis_filter_bag_end(GeisFilterBag bag GEIS_UNUSED)
 
165
{
 
166
  return NULL;
 
167
}
 
168
 
 
169
 
 
170
/*
 
171
 * Advances the iterator to the next filter in the bag.
 
172
 */
 
173
GeisFilterIterator
 
174
geis_filter_iterator_next(GeisFilterBag bag, GeisFilterIterator iter)
 
175
{
 
176
  GeisFilterIterator new_iter = iter + 1;
 
177
  if ((GeisSize)(new_iter - bag->filter_store) < bag->filter_count)
 
178
    return new_iter;
 
179
  return geis_filter_bag_end(bag);
 
180
}
 
181
 
 
182
 
 
183
/*
 
184
 * Inserts a filter in the bag.
 
185
 */
 
186
GeisStatus
 
187
geis_filter_bag_insert(GeisFilterBag bag, GeisFilter filter)
 
188
{
 
189
  GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
 
190
  if (bag->filter_count >= bag->filter_store_size)
 
191
  {
 
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));
 
195
    if (!new_store)
 
196
    {
 
197
      geis_error("failed to reallocate filter bag");
 
198
      goto error_exit;
 
199
    }
 
200
    bag->filter_store = new_store;
 
201
    bag->filter_store_size = new_store_size;
 
202
  }
 
203
  bag->filter_store[bag->filter_count++] = geis_filter_ref(filter);
 
204
  status = GEIS_STATUS_SUCCESS;
 
205
  goto final_exit;
 
206
 
 
207
error_exit:
 
208
  geis_filter_unref(filter);
 
209
final_exit:
 
210
  return status;
 
211
}
 
212
 
 
213
 
 
214
/*
 
215
 * Remoes a filter from the bag.
 
216
 */
 
217
GeisStatus
 
218
geis_filter_bag_remove(GeisFilterBag bag, GeisFilter filter)
 
219
{
 
220
  GeisSize i;
 
221
  GeisStatus status = GEIS_STATUS_SUCCESS;
 
222
  for (i = 0; i < bag->filter_count; ++i)
 
223
  {
 
224
    if (bag->filter_store[i] == filter)
 
225
    {
 
226
      GeisSize j;
 
227
      geis_filter_delete(bag->filter_store[i]);
 
228
      --bag->filter_count;
 
229
      for (j = i; j < bag->filter_count; ++j)
 
230
      {
 
231
        bag->filter_store[j] = bag->filter_store[j+1];
 
232
      }
 
233
      break;
 
234
    }
 
235
  }
 
236
  return status;
 
237
 
238
 
 
239
 
 
240
/*
 
241
 * Creates a new, empty filter object.
 
242
 */
 
243
static GeisFilter
 
244
_filter_new_empty(GeisString name)
 
245
{
 
246
  GeisFilter filter = calloc(1, sizeof(struct _GeisFilter));
 
247
  if (!filter)
 
248
  {
 
249
    geis_error("error allocating filter");
 
250
    goto final_exit;
 
251
  }
 
252
 
 
253
  if (name)
 
254
  {
 
255
    filter->name = strdup(name);
 
256
  }
 
257
  else
 
258
  {
 
259
    filter->name = strdup("");
 
260
  }
 
261
  if (!filter->name)
 
262
  {
 
263
    geis_error("error allocating filter name");
 
264
    goto unwind_filter;
 
265
  }
 
266
  filter->oid = s_filter_oid++;
 
267
  goto final_exit;
 
268
 
 
269
unwind_filter:
 
270
  free(filter);
 
271
  filter = NULL;
 
272
final_exit:
 
273
  return filter;
 
274
}
 
275
 
 
276
 
 
277
/*
 
278
 * Creates a GEIS v2.0 filter object.
 
279
 */
 
280
GeisFilter
 
281
geis_filter_new(Geis geis, GeisString name)
 
282
{
 
283
  GeisFilter filter = _filter_new_empty(name);
 
284
  if (!filter)
 
285
  {
 
286
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
 
287
    goto final_exit;
 
288
  }
 
289
 
 
290
  filter->terms = geis_filter_term_bag_new(0);
 
291
  if (!filter->terms)
 
292
  {
 
293
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
 
294
    geis_error("error allocating filter terms");
 
295
    goto unwind_filter;
 
296
  }
 
297
 
 
298
  filter->backend_token = geis_backend_token_new(geis,
 
299
                                                 GEIS_BACKEND_TOKEN_INIT_ALL);
 
300
  if (!filter->backend_token)
 
301
  {
 
302
    geis_error_push(geis, GEIS_STATUS_UNKNOWN_ERROR);
 
303
    geis_error("error allocating filter token");
 
304
    goto unwind_term_bag;
 
305
  }
 
306
 
 
307
  filter->geis = geis_ref(geis);
 
308
  geis_filter_ref(filter);
 
309
  goto final_exit;
 
310
 
 
311
unwind_term_bag:
 
312
  geis_filter_term_bag_delete(filter->terms);
 
313
unwind_filter:
 
314
  free((char *)filter->name);
 
315
  free(filter);
 
316
  filter = NULL;
 
317
final_exit:
 
318
  return filter;
 
319
}
 
320
 
 
321
 
 
322
/*
 
323
 * Creates a new filter by copying an existing filter.
 
324
 */
 
325
GeisFilter
 
326
geis_filter_clone(GeisFilter original, GeisString name)
 
327
{
 
328
  GeisFilter filter = _filter_new_empty(name);
 
329
  if (!filter)
 
330
  {
 
331
    geis_error_push(original->geis, GEIS_STATUS_UNKNOWN_ERROR);
 
332
    goto final_exit;
 
333
  }
 
334
 
 
335
  filter->terms = geis_filter_term_bag_clone(original->terms);
 
336
  if (!filter->terms)
 
337
  {
 
338
    geis_error_push(original->geis, GEIS_STATUS_UNKNOWN_ERROR);
 
339
    geis_error("error allocating filter terms");
 
340
    goto unwind_filter;
 
341
  }
 
342
 
 
343
  filter->geis = geis_ref(original->geis);
 
344
  filter->backend_token = geis_backend_token_clone(original->backend_token);
 
345
  geis_filter_ref(filter);
 
346
  goto final_exit;
 
347
 
 
348
unwind_filter:
 
349
  free((char *)filter->name);
 
350
  free(filter);
 
351
  filter = NULL;
 
352
final_exit:
 
353
  return filter;
 
354
}
 
355
 
 
356
 
 
357
/*
 
358
 * Destroys a GEIS v2.0 filter object.
 
359
 */
 
360
GeisStatus
 
361
geis_filter_delete(GeisFilter filter)
 
362
{
 
363
  GeisStatus status = GEIS_STATUS_SUCCESS;
 
364
 
 
365
  if (geis_filter_unref(filter) == 0)
 
366
  {
 
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);
 
371
    free(filter);
 
372
  }
 
373
  return status;
 
374
}
 
375
 
 
376
 
 
377
/*
 
378
 * Gets the name given to the filter when it was created.
 
379
 */
 
380
GeisString
 
381
geis_filter_name(GeisFilter filter)
 
382
{
 
383
  return filter->name;
 
384
}
 
385
 
 
386
 
 
387
/*
 
388
 * Indicates if the facility is valid.
 
389
 */
 
390
static GeisBoolean
 
391
_facility_is_valid(GeisFilterFacility facility)
 
392
{
 
393
  return facility == GEIS_FILTER_DEVICE
 
394
    ||   facility == GEIS_FILTER_CLASS
 
395
    ||   facility == GEIS_FILTER_REGION
 
396
    ||   facility == GEIS_FILTER_SPECIAL;
 
397
}
 
398
 
 
399
 
 
400
/*
 
401
 * Indicates if the operation is valid.
 
402
 */
 
403
static GeisBoolean
 
404
_operation_is_valid(GeisFilterOperation op)
 
405
{
 
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;
 
412
}
 
413
 
 
414
 
 
415
/*
 
416
 * Gets the attr description by name.
 
417
 * @todo implement this function
 
418
 */
 
419
static GeisAttrType
 
420
_get_attr_type_for_facility(Geis               geis,
 
421
                            GeisFilterFacility facility,
 
422
                            GeisString         attr_name)
 
423
{
 
424
  GeisAttrType type = GEIS_ATTR_TYPE_UNKNOWN;
 
425
  switch (facility)
 
426
  {
 
427
    case GEIS_FILTER_DEVICE:
 
428
      type = geis_get_device_attr_type(geis, attr_name);
 
429
      break;
 
430
    case GEIS_FILTER_CLASS:
 
431
      type = geis_get_class_attr_type(geis, attr_name);
 
432
      break;
 
433
    case GEIS_FILTER_REGION:
 
434
      type = geis_get_region_attr_type(geis, attr_name);
 
435
      break;
 
436
    case GEIS_FILTER_SPECIAL:
 
437
      type = geis_get_special_attr_type(geis, attr_name);
 
438
      break;
 
439
    default:
 
440
      break;
 
441
  }
 
442
  return type;
 
443
}
 
444
 
 
445
 
 
446
GeisStatus
 
447
geis_filter_add_term_internal(GeisFilter filter, GeisFilterTerm term)
 
448
{
 
449
  GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
 
450
  GeisAttr attr = geis_filter_term_attr(term);
 
451
 
 
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);
 
459
 
 
460
  return status;
 
461
}
 
462
 
 
463
 
 
464
/*
 
465
 * Adds zero or more terms to a filter.
 
466
 */
 
467
GeisStatus
 
468
geis_filter_add_term(GeisFilter         filter,
 
469
                     GeisFilterFacility facility,
 
470
                                        ...)
 
471
{
 
472
  GeisStatus status = GEIS_STATUS_UNKNOWN_ERROR;
 
473
  va_list    varargs;
 
474
  GeisString attr_name;
 
475
 
 
476
  if (!_facility_is_valid(facility))
 
477
  {
 
478
    status = GEIS_STATUS_BAD_ARGUMENT;
 
479
    geis_error_push(filter->geis, status);
 
480
    geis_error("invalid filter facility");
 
481
    goto final_exit;
 
482
  }
 
483
 
 
484
  va_start(varargs, facility);
 
485
  for (attr_name = va_arg(varargs, GeisString);
 
486
       attr_name;
 
487
       attr_name = va_arg(varargs, GeisString))
 
488
  {
 
489
    GeisAttrType attr_type = _get_attr_type_for_facility(filter->geis,
 
490
                                                         facility,
 
491
                                                         attr_name);
 
492
    if (attr_type == GEIS_ATTR_TYPE_UNKNOWN)
 
493
    {
 
494
      status = GEIS_STATUS_BAD_ARGUMENT;
 
495
      geis_error_push(filter->geis, status);
 
496
      geis_error("invalid attr name \"%s\" for facility", attr_name);
 
497
      goto final_exit;
 
498
    }
 
499
 
 
500
    GeisFilterOperation op = va_arg(varargs, GeisFilterOperation);
 
501
    if (!_operation_is_valid(op))
 
502
    {
 
503
      status = GEIS_STATUS_BAD_ARGUMENT;
 
504
      geis_error_push(filter->geis, status);
 
505
      geis_error("invalid filter operation");
 
506
      goto final_exit;
 
507
    }
 
508
 
 
509
    switch (attr_type)
 
510
    {
 
511
      case GEIS_ATTR_TYPE_BOOLEAN:
 
512
        {
 
513
          GeisBoolean value = va_arg(varargs, GeisBoolean);
 
514
          geis_filterable_attribute_foreach(filter->geis,
 
515
                                            facility,
 
516
                                            filter->backend_token,
 
517
                                            attr_name,
 
518
                                            op,
 
519
                                            &value);
 
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);
 
523
        }
 
524
        break;
 
525
 
 
526
      case GEIS_ATTR_TYPE_FLOAT:
 
527
        {
 
528
          GeisFloat value = va_arg(varargs, double);
 
529
          geis_filterable_attribute_foreach(filter->geis,
 
530
                                            facility,
 
531
                                            filter->backend_token,
 
532
                                            attr_name,
 
533
                                            op,
 
534
                                            &value);
 
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);
 
538
        }
 
539
        break;
 
540
 
 
541
      case GEIS_ATTR_TYPE_INTEGER:
 
542
        {
 
543
          GeisInteger value = va_arg(varargs, GeisInteger);
 
544
          geis_filterable_attribute_foreach(filter->geis,
 
545
                                            facility,
 
546
                                            filter->backend_token,
 
547
                                            attr_name,
 
548
                                            op,
 
549
                                            &value);
 
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);
 
553
        }
 
554
        break;
 
555
 
 
556
      case GEIS_ATTR_TYPE_POINTER:
 
557
        {
 
558
          GeisPointer value = va_arg(varargs, GeisPointer);
 
559
          geis_filterable_attribute_foreach(filter->geis,
 
560
                                            facility,
 
561
                                            filter->backend_token,
 
562
                                            attr_name,
 
563
                                            op,
 
564
                                            value);
 
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);
 
568
        }
 
569
        break;
 
570
 
 
571
      case GEIS_ATTR_TYPE_STRING:
 
572
        {
 
573
          GeisString value = va_arg(varargs, GeisString);
 
574
          geis_filterable_attribute_foreach(filter->geis,
 
575
                                            facility,
 
576
                                            filter->backend_token,
 
577
                                            attr_name,
 
578
                                            op,
 
579
                                            (void *)value);
 
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);
 
583
        }
 
584
        break;
 
585
 
 
586
      default:
 
587
        status = GEIS_STATUS_BAD_ARGUMENT;
 
588
        geis_error_push(filter->geis, status);
 
589
        geis_error("invalid filter argument");
 
590
        goto final_exit;
 
591
        break;
 
592
    }
 
593
  }
 
594
  va_end(varargs);
 
595
  status = GEIS_STATUS_SUCCESS;
 
596
 
 
597
final_exit:
 
598
  return status;
 
599
}
 
600
 
 
601
 
 
602
/*
 
603
 * Atomically increments filter refcount.
 
604
 */
 
605
GeisFilter
 
606
geis_filter_ref(GeisFilter filter)
 
607
{
 
608
  geis_atomic_ref(&filter->refcount);
 
609
  return filter;
 
610
}
 
611
 
 
612
 
 
613
/*
 
614
 * Atomically decrements and returns filter refcount.
 
615
 */
 
616
GeisSize
 
617
geis_filter_unref(GeisFilter filter)
 
618
{
 
619
  return geis_atomic_unref(&filter->refcount);
 
620
}
 
621
 
 
622
 
 
623
/*
 
624
 * Gets the number of terms in the filter.
 
625
 */
 
626
GeisSize
 
627
geis_filter_term_count(GeisFilter filter)
 
628
{
 
629
  return geis_filter_term_bag_count(filter->terms);
 
630
}
 
631
 
 
632
 
 
633
/*
 
634
 * Gets the indicated term in the filter.
 
635
 */
 
636
GeisFilterTerm
 
637
geis_filter_term(GeisFilter filter, GeisSize index)
 
638
{
 
639
  return geis_filter_term_bag_term(filter->terms, index);
 
640
}
 
641
 
 
642
/*
 
643
 * Gets the back end token from the filter.
 
644
 */
 
645
GeisBackendToken
 
646
geis_filter_token(GeisFilter filter)
 
647
{
 
648
  return filter->backend_token;
 
649
}
 
650
 
 
651
 
 
652
/*
 
653
 * Performs the filter function on a Geis event.
 
654
 */
 
655
GeisBoolean
 
656
geis_filter_pass_event(GeisFilter filter, GeisEvent event)
 
657
{
 
658
  GeisBoolean pass = GEIS_TRUE;
 
659
  for (GeisSize i = 0; i < geis_filter_term_bag_count(filter->terms); ++i)
 
660
  {
 
661
    GeisFilterTerm term = geis_filter_term_bag_term(filter->terms, i);
 
662
    pass &= geis_filter_term_match_event(term, event);
 
663
  }
 
664
  return pass;
 
665
}
 
666
 
 
667