Documentation:
[lttv.git] / ltt / branches / poly / lttv / lttv / filter.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2005 Michel Dagenais and Simon Bouvier-Zappa
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 /*! \file lttv/lttv/filter.c
20 * \brief Defines the core filter of application
21 *
22 * consist in AND, OR and NOT nested expressions, forming a tree with
23 * simple relations as leaves. The simple relations test if a field
24 * in an event is equal, not equal, smaller, smaller or equal, larger, or
25 * larger or equal to a specified value.
26 *
27 * Fields specified in a simple expression can take following
28 * values
29 *
30 * \verbatim
31 * LttvTracefileContext{}
32 * |->event\
33 * | |->name (String, converted to GQuark)
34 * | |->category (String, not yet implemented)
35 * | |->time (LttTime)
36 * | |->tsc (LttCycleCount)
37 * | |->fields
38 * | |->"event name"
39 * | |->"field name"
40 * | |->"sub-field name"
41 * | |->...
42 * | |->"leaf-field name" (field type)
43 * |->tracefile
44 * | |->name (String, converted to GQuark)
45 * |->trace
46 * | |->name (String, converted to GQuark)
47 * |->state
48 * |->pid (uint64)
49 * |->ppid (uint64)
50 * |->creation_time (LttTime)
51 * |->insertion_time (LttTime)
52 * |->process_name (String, converted to GQuark)
53 * |->execution_mode (LttvExecutionMode)
54 * |->execution_submode (LttvExecutionSubmode)
55 * |->process_status (LttvProcessStatus)
56 * |->cpu (GQuark)
57 * \endverbatim
58 */
59
60 /*
61 * TODO
62 * - refine switch of expression in multiple uses functions
63 * - remove the idle expressions in the tree ****
64 */
65
66 #include <lttv/filter.h>
67
68 /**
69 * @fn LttvSimpleExpression* lttv_simple_expression_new()
70 *
71 * Constructor for LttvSimpleExpression
72 * @return pointer to new LttvSimpleExpression
73 */
74 LttvSimpleExpression*
75 lttv_simple_expression_new() {
76
77 LttvSimpleExpression* se = g_new(LttvSimpleExpression,1);
78
79 se->field = LTTV_FILTER_UNDEFINED;
80 se->op = NULL;
81 se->offset = 0;
82
83 return se;
84 }
85
86 /**
87 * @fn gboolean lttv_simple_expression_assign_field(GPtrArray*,LttvSimpleExpression*)
88 *
89 * Parse through filtering field hierarchy as specified
90 * by user. This function compares each value to
91 * predetermined quarks
92 * @param fp The field path list
93 * @param se current simple expression
94 * @return success/failure of operation
95 */
96 gboolean
97 lttv_simple_expression_assign_field(GPtrArray* fp, LttvSimpleExpression* se) {
98
99 GString* f = NULL;
100
101 if(fp->len < 2) return FALSE;
102 g_assert(f=g_ptr_array_remove_index(fp,0));
103
104 /*
105 * Parse through the specified
106 * hardcoded fields.
107 *
108 * Take note however that the
109 * 'event' subfields might change
110 * depending on values specified
111 * in core.xml file. Hence, if
112 * none of the subfields in the
113 * array match the hardcoded
114 * subfields, it will be considered
115 * as a dynamic field
116 */
117 if(!g_strcasecmp(f->str,"trace") ) {
118 /*
119 * Possible values:
120 * trace.name
121 */
122 g_string_free(f,TRUE);
123 f=g_ptr_array_remove_index(fp,0);
124 if(!g_strcasecmp(f->str,"name")) {
125 se->field = LTTV_FILTER_TRACE_NAME;
126 }
127 } else if(!g_strcasecmp(f->str,"traceset") ) {
128 /*
129 * FIXME: not yet implemented !
130 */
131 } else if(!g_strcasecmp(f->str,"tracefile") ) {
132 /*
133 * Possible values:
134 * tracefile.name
135 */
136 g_string_free(f,TRUE);
137 f=g_ptr_array_remove_index(fp,0);
138 if(!g_strcasecmp(f->str,"name")) {
139 se->field = LTTV_FILTER_TRACEFILE_NAME;
140 }
141 } else if(!g_strcasecmp(f->str,"state") ) {
142 /*
143 * Possible values:
144 * state.pid
145 * state.ppid
146 * state.creation_time
147 * state.insertion_time
148 * state.process_name
149 * state.execution_mode
150 * state.execution_submode
151 * state.process_status
152 * state.cpu
153 */
154 g_string_free(f,TRUE);
155 f=g_ptr_array_remove_index(fp,0);
156 if(!g_strcasecmp(f->str,"pid") ) {
157 se->field = LTTV_FILTER_STATE_PID;
158 }
159 else if(!g_strcasecmp(f->str,"ppid") ) {
160 se->field = LTTV_FILTER_STATE_PPID;
161 }
162 else if(!g_strcasecmp(f->str,"creation_time") ) {
163 se->field = LTTV_FILTER_STATE_CT;
164 }
165 else if(!g_strcasecmp(f->str,"insertion_time") ) {
166 se->field = LTTV_FILTER_STATE_IT;
167 }
168 else if(!g_strcasecmp(f->str,"process_name") ) {
169 se->field = LTTV_FILTER_STATE_P_NAME;
170 }
171 else if(!g_strcasecmp(f->str,"execution_mode") ) {
172 se->field = LTTV_FILTER_STATE_EX_MODE;
173 }
174 else if(!g_strcasecmp(f->str,"execution_submode") ) {
175 se->field = LTTV_FILTER_STATE_EX_SUBMODE;
176 }
177 else if(!g_strcasecmp(f->str,"process_status") ) {
178 se->field = LTTV_FILTER_STATE_P_STATUS;
179 }
180 else if(!g_strcasecmp(f->str,"cpu") ) {
181 se->field = LTTV_FILTER_STATE_CPU;
182 }
183 } else if(!g_strcasecmp(f->str,"event") ) {
184 /*
185 * Possible values:
186 * event.name
187 * event.category
188 * event.time
189 * event.tsc
190 */
191 g_string_free(f,TRUE);
192 f=g_ptr_array_remove_index(fp,0);
193 if(!g_strcasecmp(f->str,"name") ) {
194 se->field = LTTV_FILTER_EVENT_NAME;
195 }
196 else if(!g_strcasecmp(f->str,"category") ) {
197 /*
198 * FIXME: Category not yet functional in lttv
199 */
200 se->field = LTTV_FILTER_EVENT_CATEGORY;
201 }
202 else if(!g_strcasecmp(f->str,"time") ) {
203 se->field = LTTV_FILTER_EVENT_TIME;
204 }
205 else if(!g_strcasecmp(f->str,"tsc") ) {
206 se->field = LTTV_FILTER_EVENT_TSC;
207 }
208 else { /* core.xml specified options */
209 se->field = LTTV_FILTER_EVENT_FIELD;
210 }
211 } else {
212 g_warning("Unrecognized field in filter string");
213 }
214
215 /* free memory for last string */
216 g_string_free(f,TRUE);
217
218 /* array should be empty */
219 g_assert(fp->len == 0);
220
221 if(se->field == LTTV_FILTER_UNDEFINED) {
222 g_warning("The specified field was not recognized !");
223 return FALSE;
224 }
225 return TRUE;
226 }
227
228 /**
229 * @fn gboolean lttv_simple_expression_assign_operator(LttvSimpleExpression*,LttvExpressionOp)
230 *
231 * Sets the function pointer for the current
232 * Simple Expression
233 * @param se current simple expression
234 * @param op current operator
235 * @return success/failure of operation
236 */
237 gboolean lttv_simple_expression_assign_operator(LttvSimpleExpression* se, LttvExpressionOp op) {
238
239 switch(se->field) {
240 /*
241 * string
242 */
243 case LTTV_FILTER_TRACE_NAME:
244 case LTTV_FILTER_TRACEFILE_NAME:
245 case LTTV_FILTER_STATE_P_NAME:
246 case LTTV_FILTER_EVENT_NAME:
247 switch(op) {
248 case LTTV_FIELD_EQ:
249 se->op = lttv_apply_op_eq_quark;
250 break;
251 case LTTV_FIELD_NE:
252 se->op = lttv_apply_op_ne_quark;
253 break;
254 default:
255 g_warning("Error encountered in operator assignment = or != expected");
256 return FALSE;
257 }
258 break;
259 /*
260 * integer
261 */
262 case LTTV_FILTER_STATE_PID:
263 case LTTV_FILTER_STATE_PPID:
264 case LTTV_FILTER_STATE_EX_MODE:
265 case LTTV_FILTER_STATE_EX_SUBMODE:
266 case LTTV_FILTER_STATE_P_STATUS:
267 switch(op) {
268 case LTTV_FIELD_EQ:
269 se->op = lttv_apply_op_eq_uint64;
270 break;
271 case LTTV_FIELD_NE:
272 se->op = lttv_apply_op_ne_uint64;
273 break;
274 case LTTV_FIELD_LT:
275 se->op = lttv_apply_op_lt_uint64;
276 break;
277 case LTTV_FIELD_LE:
278 se->op = lttv_apply_op_le_uint64;
279 break;
280 case LTTV_FIELD_GT:
281 se->op = lttv_apply_op_gt_uint64;
282 break;
283 case LTTV_FIELD_GE:
284 se->op = lttv_apply_op_ge_uint64;
285 break;
286 default:
287 g_warning("Error encountered in operator assignment");
288 return FALSE;
289 }
290 break;
291 /*
292 * Ltttime
293 */
294 case LTTV_FILTER_STATE_CT:
295 case LTTV_FILTER_STATE_IT:
296 case LTTV_FILTER_EVENT_TIME:
297 case LTTV_FILTER_EVENT_TSC:
298 switch(op) {
299 case LTTV_FIELD_EQ:
300 se->op = lttv_apply_op_eq_ltttime;
301 break;
302 case LTTV_FIELD_NE:
303 se->op = lttv_apply_op_ne_ltttime;
304 break;
305 case LTTV_FIELD_LT:
306 se->op = lttv_apply_op_lt_ltttime;
307 break;
308 case LTTV_FIELD_LE:
309 se->op = lttv_apply_op_le_ltttime;
310 break;
311 case LTTV_FIELD_GT:
312 se->op = lttv_apply_op_gt_ltttime;
313 break;
314 case LTTV_FIELD_GE:
315 se->op = lttv_apply_op_ge_ltttime;
316 break;
317 default:
318 g_warning("Error encountered in operator assignment");
319 return FALSE;
320 }
321 break;
322 default:
323 g_warning("Error encountered in operator assignation ! Field type:%i",se->field);
324 return FALSE;
325 }
326
327 return TRUE;
328
329 }
330
331 /**
332 * @fn gboolean lttv_simple_expression_assign_value(LttvSimpleExpression*,char*)
333 *
334 * Assign the value field to the current LttvSimpleExpression
335 * @param se pointer to the current LttvSimpleExpression
336 * @param value string value for simple expression
337 */
338 gboolean lttv_simple_expression_assign_value(LttvSimpleExpression* se, char* value) {
339
340 unsigned i;
341 gboolean is_double = FALSE;
342 LttTime t = ltt_time_zero;
343 GString* v;
344 GQuark quark;
345
346 switch(se->field) {
347 /*
348 * string --> g_quark
349 */
350 case LTTV_FILTER_TRACE_NAME:
351 case LTTV_FILTER_TRACEFILE_NAME:
352 case LTTV_FILTER_STATE_P_NAME:
353 case LTTV_FILTER_EVENT_NAME:
354 // se->value.v_string = value;
355 se->value.v_uint32 = g_quark_to_string(value);
356 g_free(value);
357 break;
358 /*
359 * integer
360 */
361 case LTTV_FILTER_STATE_PID:
362 case LTTV_FILTER_STATE_PPID:
363 case LTTV_FILTER_STATE_EX_MODE:
364 case LTTV_FILTER_STATE_EX_SUBMODE:
365 case LTTV_FILTER_STATE_P_STATUS:
366 se->value.v_uint64 = atoi(value);
367 g_free(value);
368 break;
369 /*
370 * LttTime
371 */
372 case LTTV_FILTER_STATE_CT:
373 case LTTV_FILTER_STATE_IT:
374 case LTTV_FILTER_EVENT_TIME:
375 case LTTV_FILTER_EVENT_TSC:
376 //se->value.v_double = atof(value);
377 /*
378 * parsing logic could be optimised,
379 * but as for now, simpler this way
380 */
381 v = g_string_new("");
382 for(i=0;i<strlen(value);i++) {
383 if(value[i] == '.') {
384 /* cannot specify number with more than one '.' */
385 if(is_double) return FALSE;
386 else is_double = TRUE;
387 t.tv_sec = atoi(v);
388 g_string_free(v,TRUE);
389 v = g_string_new("");
390 } else g_string_append_c(v,value[i]);
391 }
392 /* number can be integer or double */
393 if(is_double) t.tv_nsec = atoi(v);
394 else t.tv_sec = atoi(v);
395
396 g_string_free(v,TRUE);
397
398 se->value.v_ltttime = t;
399 g_free(value);
400 break;
401 default:
402 g_warning("Error encountered in value assignation ! Field type = %i",se->field);
403 g_free(value);
404 return FALSE;
405 }
406
407 return TRUE;
408
409 }
410
411 /**
412 * @fn void lttv_simple_expression_destroy(LttvSimpleExpression*)
413 *
414 * Disallocate memory for the current
415 * simple expression
416 * @param se pointer to the current LttvSimpleExpression
417 */
418 void
419 lttv_simple_expression_destroy(LttvSimpleExpression* se) {
420
421 // g_free(se->value);
422 switch(se->field) {
423 case LTTV_FILTER_TRACE_NAME:
424 case LTTV_FILTER_TRACEFILE_NAME:
425 case LTTV_FILTER_STATE_P_NAME:
426 case LTTV_FILTER_EVENT_NAME:
427 g_free(se->value.v_string);
428 break;
429 }
430 g_free(se);
431
432 }
433
434 /**
435 * @fn gint lttv_struct_type(gint)
436 *
437 * Finds the structure type depending
438 * on the fields in parameters
439 * @params ft Field of the current structure
440 * @return LttvStructType enum or -1 for error
441 */
442 gint
443 lttv_struct_type(gint ft) {
444
445 switch(ft) {
446 case LTTV_FILTER_TRACE_NAME:
447 return LTTV_FILTER_TRACE;
448 break;
449 case LTTV_FILTER_TRACEFILE_NAME:
450 return LTTV_FILTER_TRACEFILE;
451 break;
452 case LTTV_FILTER_STATE_PID:
453 case LTTV_FILTER_STATE_PPID:
454 case LTTV_FILTER_STATE_CT:
455 case LTTV_FILTER_STATE_IT:
456 case LTTV_FILTER_STATE_P_NAME:
457 case LTTV_FILTER_STATE_EX_MODE:
458 case LTTV_FILTER_STATE_EX_SUBMODE:
459 case LTTV_FILTER_STATE_P_STATUS:
460 case LTTV_FILTER_STATE_CPU:
461 return LTTV_FILTER_STATE;
462 break;
463 case LTTV_FILTER_EVENT_NAME:
464 case LTTV_FILTER_EVENT_CATEGORY:
465 case LTTV_FILTER_EVENT_TIME:
466 case LTTV_FILTER_EVENT_TSC:
467 case LTTV_FILTER_EVENT_FIELD:
468 return LTTV_FILTER_EVENT;
469 break;
470 default:
471 return -1;
472 }
473 }
474
475 /**
476 * @fn gboolean lttv_apply_op_eq_uint64(gpointer,LttvFieldValue)
477 *
478 * Applies the 'equal' operator to the
479 * specified structure and value
480 * @param v1 left member of comparison
481 * @param v2 right member of comparison
482 * @return success/failure of operation
483 */
484 gboolean lttv_apply_op_eq_uint64(const gpointer v1, LttvFieldValue v2) {
485
486 guint64* r = (guint64*) v1;
487 return (*r == v2.v_uint64);
488
489 }
490
491 /**
492 * @fn gboolean lttv_apply_op_eq_uint32(gpointer,LttvFieldValue)
493 *
494 * Applies the 'equal' operator to the
495 * specified structure and value
496 * @param v1 left member of comparison
497 * @param v2 right member of comparison
498 * @return success/failure of operation
499 */
500 gboolean lttv_apply_op_eq_uint32(const gpointer v1, LttvFieldValue v2) {
501 guint32* r = (guint32*) v1;
502 return (*r == v2.v_uint32);
503 }
504
505 /**
506 * @fn gboolean lttv_apply_op_eq_uint16(gpointer,LttvFieldValue)
507 *
508 * Applies the 'equal' operator to the
509 * specified structure and value
510 * @param v1 left member of comparison
511 * @param v2 right member of comparison
512 * @return success/failure of operation
513 */
514 gboolean lttv_apply_op_eq_uint16(const gpointer v1, LttvFieldValue v2) {
515 guint16* r = (guint16*) v1;
516 return (*r == v2.v_uint16);
517 }
518
519 /**
520 * @fn gboolean lttv_apply_op_eq_double(gpointer,LttvFieldValue)
521 *
522 * Applies the 'equal' operator to the
523 * specified structure and value
524 * @param v1 left member of comparison
525 * @param v2 right member of comparison
526 * @return success/failure of operation
527 */
528 gboolean lttv_apply_op_eq_double(const gpointer v1, LttvFieldValue v2) {
529 double* r = (double*) v1;
530 return (*r == v2.v_double);
531 }
532
533 /**
534 * @fn gboolean lttv_apply_op_eq_string(gpointer,LttvFieldValue)
535 *
536 * Applies the 'equal' operator to the
537 * specified structure and value
538 * @param v1 left member of comparison
539 * @param v2 right member of comparison
540 * @return success/failure of operation
541 */
542 gboolean lttv_apply_op_eq_string(const gpointer v1, LttvFieldValue v2) {
543 char* r = (char*) v1;
544 return (!g_strcasecmp(r,v2.v_string));
545 }
546
547 /**
548 * @fn gboolean lttv_apply_op_eq_quark(gpointer,LttvFieldValue)
549 *
550 * Applies the 'equal' operator to the
551 * specified structure and value
552 * @param v1 left member of comparison
553 * @param v2 right member of comparison
554 * @return success/failure of operation
555 */
556 gboolean lttv_apply_op_eq_quark(const gpointer v1, LttvFieldValue v2) {
557 GQuark* r = (GQuark*) v1;
558 g_print("v1:%i v2:%i\n",*r,v2.v_uint32);
559 return (*r == v2.v_uint32);
560 }
561
562 /**
563 * @fn gboolean lttv_apply_op_eq_ltttime(gpointer,LttvFieldValue)
564 *
565 * Applies the 'equal' operator to the
566 * specified structure and value
567 * @param v1 left member of comparison
568 * @param v2 right member of comparison
569 * @return success/failure of operation
570 */
571 gboolean lttv_apply_op_eq_ltttime(const gpointer v1, LttvFieldValue v2) {
572 LttTime* r = (LttTime*) v1;
573 // return ((r->tv_sec == v2.v_ltttime.tv_sec) && (r->tv_nsec == v2.v_ltttime.tv_nsec));
574 return ltt_time_compare(*r, v2.v_ltttime)==0?1:0;
575 }
576
577
578 /**
579 * @fn gboolean lttv_apply_op_ne_uint64(gpointer,LttvFieldValue)
580 *
581 * Applies the 'not equal' operator to the
582 * specified structure and value
583 * @param v1 left member of comparison
584 * @param v2 right member of comparison
585 * @return success/failure of operation
586 */
587 gboolean lttv_apply_op_ne_uint64(const gpointer v1, LttvFieldValue v2) {
588 guint64* r = (guint64*) v1;
589 return (*r != v2.v_uint64);
590 }
591
592 /**
593 * @fn gboolean lttv_apply_op_ne_uint32(gpointer,LttvFieldValue)
594 *
595 * Applies the 'not equal' operator to the
596 * specified structure and value
597 * @param v1 left member of comparison
598 * @param v2 right member of comparison
599 * @return success/failure of operation
600 */
601 gboolean lttv_apply_op_ne_uint32(const gpointer v1, LttvFieldValue v2) {
602 guint32* r = (guint32*) v1;
603 return (*r != v2.v_uint32);
604 }
605
606 /**
607 * @fn gboolean lttv_apply_op_ne_uint16(gpointer,LttvFieldValue)
608 *
609 * Applies the 'not equal' operator to the
610 * specified structure and value
611 * @param v1 left member of comparison
612 * @param v2 right member of comparison
613 * @return success/failure of operation
614 */
615 gboolean lttv_apply_op_ne_uint16(const gpointer v1, LttvFieldValue v2) {
616 guint16* r = (guint16*) v1;
617 return (*r != v2.v_uint16);
618 }
619
620 /**
621 * @fn gboolean lttv_apply_op_ne_double(gpointer,LttvFieldValue)
622 *
623 * Applies the 'not equal' operator to the
624 * specified structure and value
625 * @param v1 left member of comparison
626 * @param v2 right member of comparison
627 * @return success/failure of operation
628 */
629 gboolean lttv_apply_op_ne_double(const gpointer v1, LttvFieldValue v2) {
630 double* r = (double*) v1;
631 return (*r != v2.v_double);
632 }
633
634 /**
635 * @fn gboolean lttv_apply_op_ne_string(gpointer,LttvFieldValue)
636 *
637 * Applies the 'not equal' operator to the
638 * specified structure and value
639 * @param v1 left member of comparison
640 * @param v2 right member of comparison
641 * @return success/failure of operation
642 */
643 gboolean lttv_apply_op_ne_string(const gpointer v1, LttvFieldValue v2) {
644 char* r = (char*) v1;
645 return (g_strcasecmp(r,v2.v_string));
646 }
647
648 /**
649 * @fn gboolean lttv_apply_op_ne_quark(gpointer,LttvFieldValue)
650 *
651 * Applies the 'not equal' operator to the
652 * specified structure and value
653 * @param v1 left member of comparison
654 * @param v2 right member of comparison
655 * @return success/failure of operation
656 */
657 gboolean lttv_apply_op_ne_quark(const gpointer v1, LttvFieldValue v2) {
658 GQuark* r = (GQuark*) v1;
659 return (*r != v2.v_uint32);
660 }
661
662
663 /**
664 * @fn gboolean lttv_apply_op_ne_ltttime(gpointer,LttvFieldValue)
665 *
666 * Applies the 'not equal' operator to the
667 * specified structure and value
668 * @param v1 left member of comparison
669 * @param v2 right member of comparison
670 * @return success/failure of operation
671 */
672 gboolean lttv_apply_op_ne_ltttime(const gpointer v1, LttvFieldValue v2) {
673 LttTime* r = (LttTime*) v1;
674 return ltt_time_compare(*r, v2.v_ltttime)!=0?1:0;
675 }
676
677
678 /**
679 * @fn gboolean lttv_apply_op_lt_uint64(gpointer,LttvFieldValue)
680 *
681 * Applies the 'lower than' operator to the
682 * specified structure and value
683 * @param v1 left member of comparison
684 * @param v2 right member of comparison
685 * @return success/failure of operation
686 */
687 gboolean lttv_apply_op_lt_uint64(const gpointer v1, LttvFieldValue v2) {
688 guint64* r = (guint64*) v1;
689 return (*r < v2.v_uint64);
690 }
691
692 /**
693 * @fn gboolean lttv_apply_op_lt_uint32(gpointer,LttvFieldValue)
694 *
695 * Applies the 'lower than' operator to the
696 * specified structure and value
697 * @param v1 left member of comparison
698 * @param v2 right member of comparison
699 * @return success/failure of operation
700 */
701 gboolean lttv_apply_op_lt_uint32(const gpointer v1, LttvFieldValue v2) {
702 guint32* r = (guint32*) v1;
703 return (*r < v2.v_uint32);
704 }
705
706 /**
707 * @fn gboolean lttv_apply_op_lt_uint16(gpointer,LttvFieldValue)
708 *
709 * Applies the 'lower than' operator to the
710 * specified structure and value
711 * @param v1 left member of comparison
712 * @param v2 right member of comparison
713 * @return success/failure of operation
714 */
715 gboolean lttv_apply_op_lt_uint16(const gpointer v1, LttvFieldValue v2) {
716 guint16* r = (guint16*) v1;
717 return (*r < v2.v_uint16);
718 }
719
720 /**
721 * @fn gboolean lttv_apply_op_lt_double(gpointer,LttvFieldValue)
722 *
723 * Applies the 'lower than' operator to the
724 * specified structure and value
725 * @param v1 left member of comparison
726 * @param v2 right member of comparison
727 * @return success/failure of operation
728 */
729 gboolean lttv_apply_op_lt_double(const gpointer v1, LttvFieldValue v2) {
730 double* r = (double*) v1;
731 return (*r < v2.v_double);
732 }
733
734 /**
735 * @fn gboolean lttv_apply_op_lt_ltttime(gpointer,LttvFieldValue)
736 *
737 * Applies the 'lower than' operator to the
738 * specified structure and value
739 * @param v1 left member of comparison
740 * @param v2 right member of comparison
741 * @return success/failure of operation
742 */
743 gboolean lttv_apply_op_lt_ltttime(const gpointer v1, LttvFieldValue v2) {
744 LttTime* r = (LttTime*) v1;
745 // return ((r->tv_sec < v2.v_ltttime.tv_sec) || ((r->tv_sec == v2.v_ltttime.tv_sec) && (r->tv_nsec < v2.v_ltttime.tv_nsec)));
746 return ltt_time_compare(*r, v2.v_ltttime)==-1?1:0;
747 }
748
749
750 /**
751 * @fn gboolean lttv_apply_op_le_uint64(gpointer,LttvFieldValue)
752 *
753 * Applies the 'lower or equal' operator to the
754 * specified structure and value
755 * @param v1 left member of comparison
756 * @param v2 right member of comparison
757 * @return success/failure of operation
758 */
759 gboolean lttv_apply_op_le_uint64(const gpointer v1, LttvFieldValue v2) {
760 guint64* r = (guint64*) v1;
761 return (*r <= v2.v_uint64);
762 }
763
764 /**
765 * @fn gboolean lttv_apply_op_le_uint32(gpointer,LttvFieldValue)
766 *
767 * Applies the 'lower or equal' operator to the
768 * specified structure and value
769 * @param v1 left member of comparison
770 * @param v2 right member of comparison
771 * @return success/failure of operation
772 */
773 gboolean lttv_apply_op_le_uint32(const gpointer v1, LttvFieldValue v2) {
774 guint32* r = (guint32*) v1;
775 return (*r <= v2.v_uint32);
776 }
777
778 /**
779 * @fn gboolean lttv_apply_op_le_uint16(gpointer,LttvFieldValue)
780 *
781 * Applies the 'lower or equal' operator to the
782 * specified structure and value
783 * @param v1 left member of comparison
784 * @param v2 right member of comparison
785 * @return success/failure of operation
786 */
787 gboolean lttv_apply_op_le_uint16(const gpointer v1, LttvFieldValue v2) {
788 guint16* r = (guint16*) v1;
789 return (*r <= v2.v_uint16);
790 }
791
792 /**
793 * @fn gboolean lttv_apply_op_le_double(gpointer,LttvFieldValue)
794 *
795 * Applies the 'lower or equal' operator to the
796 * specified structure and value
797 * @param v1 left member of comparison
798 * @param v2 right member of comparison
799 * @return success/failure of operation
800 */
801 gboolean lttv_apply_op_le_double(const gpointer v1, LttvFieldValue v2) {
802 double* r = (double*) v1;
803 return (*r <= v2.v_double);
804 }
805
806 /**
807 * @fn gboolean lttv_apply_op_le_ltttime(gpointer,LttvFieldValue)
808 *
809 * Applies the 'lower or equal' operator to the
810 * specified structure and value
811 * @param v1 left member of comparison
812 * @param v2 right member of comparison
813 * @return success/failure of operation
814 */
815 gboolean lttv_apply_op_le_ltttime(const gpointer v1, LttvFieldValue v2) {
816 LttTime* r = (LttTime*) v1;
817 // return ((r->tv_sec < v2.v_ltttime.tv_sec) || ((r->tv_sec == v2.v_ltttime.tv_sec) && (r->tv_nsec <= v2.v_ltttime.tv_nsec)));
818 return ltt_time_compare(*r, v2.v_ltttime)<1?1:0;
819 }
820
821
822 /**
823 * @fn gboolean lttv_apply_op_gt_uint64(gpointer,LttvFieldValue)
824 *
825 * Applies the 'greater than' operator to the
826 * specified structure and value
827 * @param v1 left member of comparison
828 * @param v2 right member of comparison
829 * @return success/failure of operation
830 */
831 gboolean lttv_apply_op_gt_uint64(const gpointer v1, LttvFieldValue v2) {
832 guint64* r = (guint64*) v1;
833 return (*r > v2.v_uint64);
834 }
835
836 /**
837 * @fn gboolean lttv_apply_op_gt_uint32(gpointer,LttvFieldValue)
838 *
839 * Applies the 'greater than' operator to the
840 * specified structure and value
841 * @param v1 left member of comparison
842 * @param v2 right member of comparison
843 * @return success/failure of operation
844 */
845 gboolean lttv_apply_op_gt_uint32(const gpointer v1, LttvFieldValue v2) {
846 guint32* r = (guint32*) v1;
847 return (*r > v2.v_uint32);
848 }
849
850 /**
851 * @fn gboolean lttv_apply_op_gt_uint16(gpointer,LttvFieldValue)
852 *
853 * Applies the 'greater than' operator to the
854 * specified structure and value
855 * @param v1 left member of comparison
856 * @param v2 right member of comparison
857 * @return success/failure of operation
858 */
859 gboolean lttv_apply_op_gt_uint16(const gpointer v1, LttvFieldValue v2) {
860 guint16* r = (guint16*) v1;
861 return (*r > v2.v_uint16);
862 }
863
864 /**
865 * @fn gboolean lttv_apply_op_gt_double(gpointer,LttvFieldValue)
866 *
867 * Applies the 'greater than' operator to the
868 * specified structure and value
869 * @param v1 left member of comparison
870 * @param v2 right member of comparison
871 * @return success/failure of operation
872 */
873 gboolean lttv_apply_op_gt_double(const gpointer v1, LttvFieldValue v2) {
874 double* r = (double*) v1;
875 return (*r > v2.v_double);
876 }
877
878 /**
879 * @fn gboolean lttv_apply_op_gt_ltttime(gpointer,LttvFieldValue)
880 *
881 * Applies the 'greater than' operator to the
882 * specified structure and value
883 * @param v1 left member of comparison
884 * @param v2 right member of comparison
885 * @return success/failure of operation
886 */
887 gboolean lttv_apply_op_gt_ltttime(const gpointer v1, LttvFieldValue v2) {
888 LttTime* r = (LttTime*) v1;
889 // return ((r->tv_sec > v2.v_ltttime.tv_sec) || ((r->tv_sec == v2.v_ltttime.tv_sec) && (r->tv_nsec > v2.v_ltttime.tv_nsec)));
890 return ltt_time_compare(*r, v2.v_ltttime)==1?1:0;
891 }
892
893
894 /**
895 * @fn gboolean lttv_apply_op_ge_uint64(gpointer,LttvFieldValue)
896 *
897 * Applies the 'greater or equal' operator to the
898 * specified structure and value
899 * @param v1 left member of comparison
900 * @param v2 right member of comparison
901 * @return success/failure of operation
902 */
903 gboolean lttv_apply_op_ge_uint64(const gpointer v1, LttvFieldValue v2) {
904 guint64* r = (guint64*) v1;
905 return (*r >= v2.v_uint64);
906 }
907
908 /**
909 * @fn gboolean lttv_apply_op_ge_uint32(gpointer,LttvFieldValue)
910 *
911 * Applies the 'greater or equal' operator to the
912 * specified structure and value
913 * @param v1 left member of comparison
914 * @param v2 right member of comparison
915 * @return success/failure of operation
916 */
917 gboolean lttv_apply_op_ge_uint32(const gpointer v1, LttvFieldValue v2) {
918 guint32* r = (guint32*) v1;
919 return (*r >= v2.v_uint32);
920 }
921
922 /**
923 * @fn gboolean lttv_apply_op_ge_uint16(gpointer,LttvFieldValue)
924 *
925 * Applies the 'greater or equal' operator to the
926 * specified structure and value
927 * @param v1 left member of comparison
928 * @param v2 right member of comparison
929 * @return success/failure of operation
930 */
931 gboolean lttv_apply_op_ge_uint16(const gpointer v1, LttvFieldValue v2) {
932 guint16* r = (guint16*) v1;
933 return (*r >= v2.v_uint16);
934 }
935
936 /**
937 * @fn gboolean lttv_apply_op_ge_double(gpointer,LttvFieldValue)
938 *
939 * Applies the 'greater or equal' operator to the
940 * specified structure and value
941 * @param v1 left member of comparison
942 * @param v2 right member of comparison
943 * @return success/failure of operation
944 */
945 gboolean lttv_apply_op_ge_double(const gpointer v1, LttvFieldValue v2) {
946 double* r = (double*) v1;
947 return (*r >= v2.v_double);
948 }
949
950 /**
951 * @fn gboolean lttv_apply_op_ge_ltttime(gpointer,LttvFieldValue)
952 *
953 * Applies the 'greater or equal' operator to the
954 * specified structure and value
955 * @param v1 left member of comparison
956 * @param v2 right member of comparison
957 * @return success/failure of operation
958 */
959 gboolean lttv_apply_op_ge_ltttime(const gpointer v1, LttvFieldValue v2) {
960 LttTime* r = (LttTime*) v1;
961 // return ((r->tv_sec > v2.v_ltttime.tv_sec) || ((r->tv_sec == v2.v_ltttime.tv_sec) && (r->tv_nsec >= v2.v_ltttime.tv_nsec)));
962 return ltt_time_compare(*r, v2.v_ltttime)>-1?1:0;
963 }
964
965
966
967 /**
968 * Makes a copy of the current filter tree
969 * @param tree pointer to the current tree
970 * @return new copy of the filter tree
971 */
972 LttvFilterTree*
973 lttv_filter_tree_clone(const LttvFilterTree* tree) {
974
975 LttvFilterTree* newtree = lttv_filter_tree_new();
976
977 newtree->node = tree->node;
978
979 newtree->left = tree->left;
980 if(newtree->left == LTTV_TREE_NODE) {
981 newtree->l_child.t = lttv_filter_tree_clone(tree->l_child.t);
982 } else if(newtree->left == LTTV_TREE_LEAF) {
983 newtree->l_child.leaf = lttv_simple_expression_new();
984 newtree->l_child.leaf->field = tree->l_child.leaf->field;
985 newtree->l_child.leaf->offset = tree->l_child.leaf->offset;
986 newtree->l_child.leaf->op = tree->l_child.leaf->op;
987 /* FIXME: special case for string copy ! */
988 newtree->l_child.leaf->value = tree->l_child.leaf->value;
989 }
990
991 newtree->right = tree->right;
992 if(newtree->right == LTTV_TREE_NODE) {
993 newtree->r_child.t = lttv_filter_tree_clone(tree->r_child.t);
994 } else if(newtree->right == LTTV_TREE_LEAF) {
995 newtree->r_child.leaf = lttv_simple_expression_new();
996 newtree->r_child.leaf->field = tree->r_child.leaf->field;
997 newtree->r_child.leaf->offset = tree->r_child.leaf->offset;
998 newtree->r_child.leaf->op = tree->r_child.leaf->op;
999 newtree->r_child.leaf->value = tree->r_child.leaf->value;
1000 }
1001
1002 return newtree;
1003
1004 }
1005
1006 /**
1007 * Makes a copy of the current filter
1008 * @param filter pointer to the current filter
1009 * @return new copy of the filter
1010 */
1011 LttvFilter*
1012 lttv_filter_clone(const LttvFilter* filter) {
1013
1014 LttvFilter* newfilter = g_new(LttvFilter,1);
1015
1016 strcpy(newfilter->expression,filter->expression);
1017
1018 newfilter->head = lttv_filter_tree_clone(filter->head);
1019
1020 return newfilter;
1021
1022 }
1023
1024
1025 /**
1026 * @fn LttvFilter* lttv_filter_new()
1027 *
1028 * Creates a new LttvFilter
1029 * @return the current LttvFilter or NULL if error
1030 */
1031 LttvFilter*
1032 lttv_filter_new() {
1033
1034 LttvFilter* filter = g_new(LttvFilter,1);
1035 filter->expression = NULL;
1036 filter->head = NULL;
1037
1038 return filter;
1039
1040 }
1041
1042 /**
1043 * @fn gboolean lttv_filter_update(LttvFilter*)
1044 *
1045 * Updates the current LttvFilter by building
1046 * its tree based upon the expression string
1047 * @param filter pointer to the current LttvFilter
1048 * @return Failure/Success of operation
1049 */
1050 gboolean
1051 lttv_filter_update(LttvFilter* filter) {
1052
1053 // g_print("filter::lttv_filter_new()\n"); /* debug */
1054
1055 if(filter->expression == NULL) return FALSE;
1056
1057 int
1058 i,
1059 p_nesting=0; /* parenthesis nesting value */
1060
1061 /* trees */
1062 LttvFilterTree
1063 *tree = lttv_filter_tree_new(), /* main tree */
1064 *subtree = NULL, /* buffer for subtrees */
1065 *t1, /* buffer #1 */
1066 *t2; /* buffer #2 */
1067
1068 /*
1069 * the filter
1070 * If the tree already exists,
1071 * destroy it and build a new one
1072 */
1073 if(filter->head != NULL) lttv_filter_tree_destroy(filter->head);
1074 filter->head = NULL; /* will be assigned at the end */
1075
1076 /*
1077 * Tree Stack
1078 * each element of the list
1079 * is a sub tree created
1080 * by the use of parenthesis in the
1081 * global expression. The final tree
1082 * will be the one left at the root of
1083 * the list
1084 */
1085 GPtrArray *tree_stack = g_ptr_array_new();
1086 g_ptr_array_add( tree_stack,(gpointer) tree );
1087
1088 /* temporary values */
1089 GString *a_field_component = g_string_new("");
1090 GPtrArray *a_field_path = g_ptr_array_new();
1091
1092 /* simple expression buffer */
1093 LttvSimpleExpression* a_simple_expression = lttv_simple_expression_new();
1094
1095 /*
1096 * Parse entire expression and construct
1097 * the binary tree. There are two steps
1098 * in browsing that string
1099 * 1. finding boolean ops " &,|,^,! " and parenthesis " {,(,[,],),} "
1100 * 2. finding simple expressions
1101 * - field path ( separated by dots )
1102 * - op ( >, <, =, >=, <=, !=)
1103 * - value ( integer, string ... )
1104 * To spare computing time, the whole
1105 * string is parsed in this loop for a
1106 * O(n) complexity order.
1107 *
1108 * When encountering logical op &,|,^
1109 * 1. parse the last value if any
1110 * 2. create a new tree
1111 * 3. add the expression (simple exp, or exp (subtree)) to the tree
1112 * 4. concatenate this tree with the current tree on top of the stack
1113 * When encountering math ops >,>=,<,<=,=,!=
1114 * 1. add to op to the simple expression
1115 * 2. concatenate last field component to field path
1116 * When encountering concatening ops .
1117 * 1. concatenate last field component to field path
1118 * When encountering opening parenthesis (,{,[
1119 * 1. create a new subtree on top of tree stack
1120 * When encountering closing parenthesis ),},]
1121 * 1. add the expression on right child of the current tree
1122 * 2. the subtree is completed, allocate a new subtree
1123 * 3. pop the tree value from the tree stack
1124 */
1125
1126 for(i=0;i<strlen(filter->expression);i++) {
1127 // debug
1128 //g_print("%c ",filter->expression[i]);
1129
1130 switch(filter->expression[i]) {
1131 /*
1132 * logical operators
1133 */
1134 case '&': /* and */
1135
1136 t1 = (LttvFilterTree*)g_ptr_array_index(tree_stack,tree_stack->len-1);
1137 while(t1->right != LTTV_TREE_IDLE) {
1138 g_assert(t1->right == LTTV_TREE_NODE);
1139 t1 = t1->r_child.t;
1140 }
1141 t2 = lttv_filter_tree_new();
1142 t2->node = LTTV_LOGICAL_AND;
1143 if(subtree != NULL) { /* append subtree to current tree */
1144 t2->left = LTTV_TREE_NODE;
1145 t2->l_child.t = subtree;
1146 subtree = NULL;
1147 t1->right = LTTV_TREE_NODE;
1148 t1->r_child.t = t2;
1149 } else { /* append a simple expression */
1150 lttv_simple_expression_assign_value(a_simple_expression,g_string_free(a_field_component,FALSE));
1151 a_field_component = g_string_new("");
1152 t2->left = LTTV_TREE_LEAF;
1153 t2->l_child.leaf = a_simple_expression;
1154 a_simple_expression = lttv_simple_expression_new();
1155 t1->right = LTTV_TREE_NODE;
1156 t1->r_child.t = t2;
1157 }
1158 break;
1159
1160 case '|': /* or */
1161
1162 t1 = (LttvFilterTree*)g_ptr_array_index(tree_stack,tree_stack->len-1);
1163 while(t1->right != LTTV_TREE_IDLE) {
1164 g_assert(t1->right == LTTV_TREE_NODE);
1165 t1 = t1->r_child.t;
1166 }
1167 t2 = lttv_filter_tree_new();
1168 t2->node = LTTV_LOGICAL_OR;
1169 if(subtree != NULL) { /* append subtree to current tree */
1170 t2->left = LTTV_TREE_NODE;
1171 t2->l_child.t = subtree;
1172 subtree = NULL;
1173 t1->right = LTTV_TREE_NODE;
1174 t1->r_child.t = t2;
1175 } else { /* append a simple expression */
1176 lttv_simple_expression_assign_value(a_simple_expression,g_string_free(a_field_component,FALSE));
1177 a_field_component = g_string_new("");
1178 t2->left = LTTV_TREE_LEAF;
1179 t2->l_child.leaf = a_simple_expression;
1180 a_simple_expression = lttv_simple_expression_new();
1181 t1->right = LTTV_TREE_NODE;
1182 t1->r_child.t = t2;
1183 }
1184 break;
1185
1186 case '^': /* xor */
1187
1188 t1 = (LttvFilterTree*)g_ptr_array_index(tree_stack,tree_stack->len-1);
1189 while(t1->right != LTTV_TREE_IDLE) {
1190 g_assert(t1->right == LTTV_TREE_NODE);
1191 t1 = t1->r_child.t;
1192 }
1193 t2 = lttv_filter_tree_new();
1194 t2->node = LTTV_LOGICAL_XOR;
1195 if(subtree != NULL) { /* append subtree to current tree */
1196 t2->left = LTTV_TREE_NODE;
1197 t2->l_child.t = subtree;
1198 subtree = NULL;
1199 t1->right = LTTV_TREE_NODE;
1200 t1->r_child.t = t2;
1201 } else { /* append a simple expression */
1202 lttv_simple_expression_assign_value(a_simple_expression,g_string_free(a_field_component,FALSE));
1203 a_field_component = g_string_new("");
1204 t2->left = LTTV_TREE_LEAF;
1205 t2->l_child.leaf = a_simple_expression;
1206 a_simple_expression = lttv_simple_expression_new();
1207 t1->right = LTTV_TREE_NODE;
1208 t1->r_child.t = t2;
1209 }
1210 break;
1211
1212 case '!': /* not, or not equal (math op) */
1213
1214 if(filter->expression[i+1] == '=') { /* != */
1215 g_ptr_array_add( a_field_path,(gpointer) a_field_component );
1216 lttv_simple_expression_assign_field(a_field_path,a_simple_expression);
1217 a_field_component = g_string_new("");
1218 lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_NE);
1219 i++;
1220 } else { /* ! */
1221 t1 = (LttvFilterTree*)g_ptr_array_index(tree_stack,tree_stack->len-1);
1222 while(t1->right != LTTV_TREE_IDLE) {
1223 g_assert(t1->right == LTTV_TREE_NODE);
1224 t1 = t1->r_child.t;
1225 }
1226 t2 = lttv_filter_tree_new();
1227 t2->node = LTTV_LOGICAL_NOT;
1228 t1->right = LTTV_TREE_NODE;
1229 t1->r_child.t = t2;
1230 }
1231 break;
1232
1233 case '(': /* start of parenthesis */
1234 case '[':
1235 case '{':
1236
1237 p_nesting++; /* incrementing parenthesis nesting value */
1238 t1 = lttv_filter_tree_new();
1239 g_ptr_array_add( tree_stack,(gpointer) t1 );
1240 break;
1241
1242 case ')': /* end of parenthesis */
1243 case ']':
1244 case '}':
1245
1246 p_nesting--; /* decrementing parenthesis nesting value */
1247 if(p_nesting<0 || tree_stack->len<2) {
1248 g_warning("Wrong filtering options, the string\n\"%s\"\n\
1249 is not valid due to parenthesis incorrect use",filter->expression);
1250 return FALSE;
1251 }
1252
1253 /* there must at least be the root tree left in the array */
1254 g_assert(tree_stack->len>0);
1255
1256 if(subtree != NULL) { /* append subtree to current tree */
1257 t1 = g_ptr_array_index(tree_stack,tree_stack->len-1);
1258 while(t1->right != LTTV_TREE_IDLE) {
1259 g_assert(t1->right == LTTV_TREE_NODE);
1260 t1 = t1->r_child.t;
1261 }
1262 t1->right = LTTV_TREE_NODE;
1263 t1->r_child.t = subtree;
1264 subtree = g_ptr_array_index(tree_stack,tree_stack->len-1);
1265 g_ptr_array_remove_index(tree_stack,tree_stack->len-1);
1266 } else { /* assign subtree as current tree */
1267 lttv_simple_expression_assign_value(a_simple_expression,g_string_free(a_field_component,FALSE));
1268 a_field_component = g_string_new("");
1269 t1 = g_ptr_array_index(tree_stack,tree_stack->len-1);
1270 while(t1->right != LTTV_TREE_IDLE) {
1271 g_assert(t1->right == LTTV_TREE_NODE);
1272 g_assert(t1->r_child.t != NULL);
1273 t1 = t1->r_child.t;
1274 }
1275 t1->right = LTTV_TREE_LEAF;
1276 t1->r_child.leaf = a_simple_expression;
1277 a_simple_expression = lttv_simple_expression_new();
1278 subtree = g_ptr_array_remove_index(tree_stack,tree_stack->len-1);
1279 }
1280 break;
1281
1282 /*
1283 * mathematic operators
1284 */
1285 case '<': /* lower, lower or equal */
1286
1287 g_ptr_array_add( a_field_path,(gpointer) a_field_component );
1288 lttv_simple_expression_assign_field(a_field_path,a_simple_expression);
1289 a_field_component = g_string_new("");
1290 if(filter->expression[i+1] == '=') { /* <= */
1291 i++;
1292 lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_LE);
1293 } else lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_LT);
1294 break;
1295
1296 case '>': /* higher, higher or equal */
1297
1298 g_ptr_array_add( a_field_path,(gpointer) a_field_component );
1299 lttv_simple_expression_assign_field(a_field_path,a_simple_expression);
1300 a_field_component = g_string_new("");
1301 if(filter->expression[i+1] == '=') { /* >= */
1302 i++;
1303 lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_GE);
1304 } else lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_GT);
1305 break;
1306
1307 case '=': /* equal */
1308
1309 g_ptr_array_add( a_field_path,(gpointer) a_field_component );
1310 lttv_simple_expression_assign_field(a_field_path,a_simple_expression);
1311 a_field_component = g_string_new("");
1312 lttv_simple_expression_assign_operator(a_simple_expression,LTTV_FIELD_EQ);
1313 break;
1314
1315 /*
1316 * Field concatening caracter
1317 */
1318 case '.': /* dot */
1319
1320 /*
1321 * divide field expression into elements
1322 * in a_field_path array.
1323 *
1324 * A dot can also be present in double values
1325 */
1326 if(a_simple_expression->field == LTTV_FILTER_UNDEFINED) {
1327 g_ptr_array_add( a_field_path,(gpointer) a_field_component );
1328 a_field_component = g_string_new("");
1329 }
1330 break;
1331 case ' ': /* ignore */
1332 case '\n': /* ignore */
1333 break;
1334 default: /* concatening current string */
1335 g_string_append_c(a_field_component,filter->expression[i]);
1336 }
1337 }
1338
1339 /*
1340 * Preliminary check to see
1341 * if tree was constructed correctly
1342 */
1343 if( p_nesting>0 ) {
1344 g_warning("Wrong filtering options, the string\n\"%s\"\n\
1345 is not valid due to parenthesis incorrect use",filter->expression);
1346 return FALSE;
1347 }
1348
1349 if(tree_stack->len != 1) /* only root tree should remain */
1350 return FALSE;
1351
1352 /* processing last element of expression */
1353 t1 = g_ptr_array_index(tree_stack,tree_stack->len-1);
1354 while(t1->right != LTTV_TREE_IDLE) {
1355 g_assert(t1->right == LTTV_TREE_NODE);
1356 t1 = t1->r_child.t;
1357 }
1358 if(subtree != NULL) { /* add the subtree */
1359 t1->right = LTTV_TREE_NODE;
1360 t1->r_child.t = subtree;
1361 subtree = NULL;
1362 } else { /* add a leaf */
1363 lttv_simple_expression_assign_value(a_simple_expression,g_string_free(a_field_component,FALSE));
1364 a_field_component = NULL;
1365 t1->right = LTTV_TREE_LEAF;
1366 t1->r_child.leaf = a_simple_expression;
1367 a_simple_expression = NULL;
1368 }
1369
1370
1371 /* free the pointer array */
1372 g_assert(a_field_path->len == 0);
1373 g_ptr_array_free(a_field_path,TRUE);
1374
1375 /* free the tree stack -- but keep the root tree */
1376 filter->head = g_ptr_array_remove_index(tree_stack,0);
1377 g_ptr_array_free(tree_stack,TRUE);
1378
1379 /* free the field buffer if allocated */
1380 if(a_field_component != NULL) g_string_free(a_field_component,TRUE);
1381
1382 /* free the simple expression buffer if allocated */
1383 if(a_simple_expression != NULL) lttv_simple_expression_destroy(a_simple_expression);
1384
1385 g_assert(filter->head != NULL); /* tree should exist */
1386 g_assert(subtree == NULL); /* remaining subtree should be included in main tree */
1387
1388 /* debug */
1389 g_print("+++++++++++++++ BEGIN PRINT ++++++++++++++++\n");
1390 lttv_print_tree(filter->head) ;
1391 g_print("+++++++++++++++ END PRINT ++++++++++++++++++\n");
1392
1393 /* success */
1394 return TRUE;
1395
1396 }
1397
1398 /**
1399 * @fn void lttv_filter_destroy(LttvFilter*)
1400 *
1401 * Destroy the current LttvFilter
1402 * @param filter pointer to the current LttvFilter
1403 */
1404 void
1405 lttv_filter_destroy(LttvFilter* filter) {
1406
1407 g_free(filter->expression);
1408 lttv_filter_tree_destroy(filter->head);
1409 g_free(filter);
1410
1411 }
1412
1413 /**
1414 * @fn LttvFilterTree* lttv_filter_tree_new()
1415 *
1416 * Assign a new tree for the current expression
1417 * or sub expression
1418 * @return pointer of LttvFilterTree
1419 */
1420 LttvFilterTree*
1421 lttv_filter_tree_new() {
1422 LttvFilterTree* tree;
1423
1424 tree = g_new(LttvFilterTree,1);
1425 tree->node = 0; //g_new(lttv_expression,1);
1426 tree->left = LTTV_TREE_IDLE;
1427 tree->right = LTTV_TREE_IDLE;
1428 tree->r_child.t = NULL;
1429 tree->l_child.t = NULL;
1430
1431 return tree;
1432 }
1433
1434 /**
1435 * @fn void lttv_filter_append_expression(LttvFilter*,char*)
1436 *
1437 * Append a new expression to the expression
1438 * defined in the current filter
1439 * @param filter pointer to the current LttvFilter
1440 * @param expression string that must be appended
1441 * @return Success/Failure of operation
1442 */
1443 gboolean lttv_filter_append_expression(LttvFilter* filter, const char *expression) {
1444
1445 if(expression == NULL) return FALSE;
1446 if(filter == NULL) return FALSE;
1447
1448 GString* s = g_string_new("");
1449 if(filter->expression != NULL) {
1450 g_string_append(s,filter->expression);
1451 g_string_append_c(s,'&');
1452 }
1453 g_string_append(s,expression);
1454
1455 filter->expression = g_string_free(s,FALSE);
1456
1457 /* TRUE if construction of tree proceeded without errors */
1458 return lttv_filter_update(filter);
1459
1460 }
1461
1462 /**
1463 * @fn void lttv_filter_clear_expression(LttvFilter*)
1464 *
1465 * Clear the filter expression from the
1466 * current filter and sets its pointer to NULL
1467 * @param filter pointer to the current LttvFilter
1468 */
1469 void lttv_filter_clear_expression(LttvFilter* filter) {
1470
1471 if(filter->expression != NULL) {
1472 g_free(filter->expression);
1473 filter->expression = NULL;
1474 }
1475
1476 }
1477
1478 /**
1479 * @fn void lttv_filter_tree_destroy(LttvFilterTree*)
1480 *
1481 * Destroys the tree and his sub-trees
1482 * @param tree Tree which must be destroyed
1483 */
1484 void
1485 lttv_filter_tree_destroy(LttvFilterTree* tree) {
1486
1487 if(tree == NULL) return;
1488
1489 if(tree->left == LTTV_TREE_LEAF) lttv_simple_expression_destroy(tree->l_child.leaf);
1490 else if(tree->left == LTTV_TREE_NODE) lttv_filter_tree_destroy(tree->l_child.t);
1491
1492 if(tree->right == LTTV_TREE_LEAF) lttv_simple_expression_destroy(tree->r_child.leaf);
1493 else if(tree->right == LTTV_TREE_NODE) lttv_filter_tree_destroy(tree->r_child.t);
1494
1495 // g_free(tree->node);
1496 g_free(tree);
1497 }
1498
1499 /**
1500 * Global parsing function for the current
1501 * LttvFilterTree
1502 * @param t pointer to the current LttvFilterTree
1503 * @param event current LttEvent, NULL if not used
1504 * @param tracefile current LttTracefile, NULL if not used
1505 * @param trace current LttTrace, NULL if not used
1506 * @param state current LttvProcessState, NULL if not used
1507 * @param context current LttvTracefileContext, NULL if not used
1508 * @return response of filter
1509 */
1510 gboolean
1511 lttv_filter_tree_parse(
1512 const LttvFilterTree* t,
1513 const LttEvent* event,
1514 const LttTracefile* tracefile,
1515 const LttTrace* trace,
1516 const LttvProcessState* state,
1517 const LttvTracefileContext* context
1518 /*,...*/)
1519 {
1520
1521 /*
1522 * Each tree is parsed in inorder.
1523 * This way, it's possible to apply the left filter of the
1524 * tree, then decide whether or not the right branch should
1525 * be parsed depending on the linking logical operator
1526 *
1527 * Each node consists in a
1528 * 1. logical operator
1529 * 2. left child ( node or simple expression )
1530 * 3. right child ( node or simple expression )
1531 *
1532 * When the child is a simple expression, we must
1533 * before all determine if the expression refers to
1534 * a structure which is whithin observation ( not NULL ).
1535 * -If so, the expression is evaluated.
1536 * -If not, the result is set to TRUE since this particular
1537 * operation does not interfere with the lttv structure
1538 *
1539 * The result of each simple expression will directly
1540 * affect the next branch. This way, depending on
1541 * the linking logical operator, the parser will decide
1542 * to explore or not the next branch.
1543 * 1. AND OPERATOR
1544 * -If result of left branch is 0 / FALSE
1545 * then don't explore right branch and return 0;
1546 * -If result of left branch is 1 / TRUE then explore
1547 * 2. OR OPERATOR
1548 * -If result of left branch is 1 / TRUE
1549 * then don't explore right branch and return 1;
1550 * -If result of left branch is 0 / FALSE then explore
1551 * 3. XOR OPERATOR
1552 * -Result of left branch will not affect exploration of
1553 * right branch
1554 */
1555
1556 gboolean lresult = FALSE, rresult = FALSE;
1557
1558 /*
1559 * Parse left branch
1560 */
1561 if(t->left == LTTV_TREE_NODE) {
1562 lresult = lttv_filter_tree_parse(t->l_child.t,event,tracefile,trace,state,context);
1563 }
1564 else if(t->left == LTTV_TREE_LEAF) {
1565 lresult = lttv_filter_tree_parse_branch(t->l_child.leaf,event,tracefile,trace,state,context);
1566 }
1567
1568 /*
1569 * Parse linking operator
1570 * make a cutoff if possible
1571 */
1572 if((t->node & LTTV_LOGICAL_OR) && lresult == TRUE) return TRUE;
1573 if((t->node & LTTV_LOGICAL_AND) && lresult == FALSE) return FALSE;
1574
1575 /*
1576 * Parse right branch
1577 */
1578 if(t->right == LTTV_TREE_NODE) {
1579 rresult = lttv_filter_tree_parse(t->r_child.t,event,tracefile,trace,state,context);
1580 }
1581 else if(t->right == LTTV_TREE_LEAF) {
1582 rresult = lttv_filter_tree_parse_branch(t->r_child.leaf,event,tracefile,trace,state,context);
1583 }
1584
1585 /*
1586 * Apply and return the
1587 * logical link between the
1588 * two operation
1589 */
1590 switch(t->node) {
1591 case LTTV_LOGICAL_OR: return (lresult | rresult);
1592 case LTTV_LOGICAL_AND: return (lresult & rresult);
1593 case LTTV_LOGICAL_NOT: return (!rresult);
1594 case LTTV_LOGICAL_XOR: return (lresult ^ rresult);
1595 case 0: return (rresult);
1596 default:
1597 /*
1598 * This case should never be
1599 * parsed, if so, this subtree
1600 * is cancelled !
1601 */
1602 return TRUE;
1603 }
1604
1605 }
1606
1607 /**
1608 * This function parses a particular branch of the tree
1609 * @param se pointer to the current LttvSimpleExpression
1610 * @param event current LttEvent, NULL if not used
1611 * @param tracefile current LttTracefile, NULL if not used
1612 * @param trace current LttTrace, NULL if not used
1613 * @param state current LttvProcessState, NULL if not used
1614 * @param context current LttvTracefileContext, NULL if not used
1615 * @return response of filter
1616 */
1617 gboolean lttv_filter_tree_parse_branch(
1618 const LttvSimpleExpression* se,
1619 const LttEvent* event,
1620 const LttTracefile* tracefile,
1621 const LttTrace* trace,
1622 const LttvProcessState* state,
1623 const LttvTracefileContext* context) {
1624
1625 LttvFieldValue v;
1626 v = se->value;
1627 switch(se->field) {
1628 case LTTV_FILTER_TRACE_NAME:
1629 if(trace == NULL) return TRUE;
1630 else {
1631 GQuark quark = g_quark_to_string(ltt_trace_name(trace));
1632 return se->op((gpointer)&quark,v);
1633 }
1634 break;
1635 case LTTV_FILTER_TRACEFILE_NAME:
1636 if(tracefile == NULL) return TRUE;
1637 else {
1638 GQuark quark = g_quark_to_string(ltt_tracefile_name(tracefile));
1639 return se->op((gpointer)&quark,v);
1640 }
1641 break;
1642 case LTTV_FILTER_STATE_PID:
1643 if(state == NULL) return TRUE;
1644 else return se->op((gpointer)&state->pid,v);
1645 break;
1646 case LTTV_FILTER_STATE_PPID:
1647 if(state == NULL) return TRUE;
1648 else return se->op((gpointer)&state->ppid,v);
1649 break;
1650 case LTTV_FILTER_STATE_CT:
1651 if(state == NULL) return TRUE;
1652 else {
1653 return se->op((gpointer)&state->creation_time,v);
1654 }
1655 break;
1656 case LTTV_FILTER_STATE_IT:
1657 if(state == NULL) return TRUE;
1658 else {
1659 return se->op((gpointer)&state->insertion_time,v);
1660 }
1661 break;
1662 case LTTV_FILTER_STATE_P_NAME:
1663 /*
1664 * All 'unnamed' for the moment
1665 */
1666 if(state == NULL) return TRUE;
1667 else {
1668 GQuark quark = g_quark_to_string(state->name);
1669 return se->op((gpointer)&quark,v);
1670 }
1671 break;
1672 case LTTV_FILTER_STATE_EX_MODE:
1673 if(state == NULL) return TRUE;
1674 else return se->op((gpointer)&state->state->t,v);
1675 break;
1676 case LTTV_FILTER_STATE_EX_SUBMODE:
1677 if(state == NULL) return TRUE;
1678 else return se->op((gpointer)&state->state->n,v);
1679 break;
1680 case LTTV_FILTER_STATE_P_STATUS:
1681 if(state == NULL) return TRUE;
1682 else return se->op((gpointer)&state->state->s,v);
1683 break;
1684 case LTTV_FILTER_STATE_CPU:
1685 if(context == NULL) return TRUE;
1686 else {
1687 /* FIXME: not sure of that one */
1688 return se->op((gpointer)g_quark_to_string(((LttvTracefileState*)context)->cpu_name),v);
1689 }
1690 break;
1691 case LTTV_FILTER_EVENT_NAME:
1692 if(event == NULL) return TRUE;
1693 else {
1694 LttEventType* et;
1695 et = ltt_event_eventtype(event);
1696 g_print("v:%s\n",ltt_eventtype_name(et));
1697 GQuark quark = g_quark_to_string(ltt_eventtype_name(et));
1698 return se->op((gpointer)&quark,v);
1699 }
1700 break;
1701
1702 case LTTV_FILTER_EVENT_CATEGORY:
1703 /*
1704 * TODO: Not yet implemented
1705 */
1706 return TRUE;
1707 break;
1708 case LTTV_FILTER_EVENT_TIME:
1709 if(event == NULL) return TRUE;
1710 else {
1711 LttTime time = ltt_event_time(event);
1712 return se->op((gpointer)&time,v);
1713 }
1714 break;
1715 case LTTV_FILTER_EVENT_TSC:
1716 // if(event == NULL) return TRUE;
1717 // else {
1718 // double val = ltt_time_to_double(event->event_time);
1719 // return se->op((gpointer)&val,v);
1720 // }
1721 /*
1722 * FIXME: Where is event.tsc
1723 */
1724 return TRUE;
1725 break;
1726 case LTTV_FILTER_EVENT_FIELD:
1727 /*
1728 * TODO: Use the offset to
1729 * find the dynamic field
1730 * in the event struct
1731 */
1732 return TRUE;
1733 default:
1734 /*
1735 * This case should never be
1736 * parsed, if so, the whole
1737 * filtering is cancelled
1738 */
1739 g_warning("Error while parsing the filter tree");
1740 return TRUE;
1741 }
1742
1743 /* should never get here */
1744 return TRUE;
1745
1746 }
1747
1748
1749
1750 /**
1751 * Debug function. Prints tree memory allocation.
1752 * @param t the pointer to the current LttvFilterTree
1753 */
1754 void
1755 lttv_print_tree(const LttvFilterTree* t) {
1756
1757 g_print("node:%p lchild:%p rchild:%p\n",t, //t->l_child.t,t->r_child.t);
1758 (t->left==LTTV_TREE_NODE)?t->l_child.t:NULL,
1759 (t->right==LTTV_TREE_NODE)?t->r_child.t:NULL);
1760 g_print("node type: %i / [left] %i / [right] %i\n",t->node,t->left,t->right);
1761 if(t->left == LTTV_TREE_NODE) lttv_print_tree(t->l_child.t);
1762 else if(t->left == LTTV_TREE_LEAF) {
1763 g_print("%p: left is %i %p value\n",t,t->l_child.leaf->field,t->l_child.leaf->op);
1764 }
1765 if(t->right == LTTV_TREE_NODE) lttv_print_tree(t->r_child.t);
1766 else if(t->right == LTTV_TREE_LEAF) {
1767 g_print("%p: right is %i %p value\n",t,t->r_child.leaf->field,t->r_child.leaf->op);
1768 }
1769
1770 }
1771
1772 /**
1773 * @fn static void module_init()
1774 *
1775 * Initializes the filter module and specific values
1776 */
1777 static void module_init()
1778 {
1779
1780 }
1781
1782 /**
1783 * Destroys the filter module and specific values
1784 */
1785 static void module_destroy()
1786 {
1787
1788 }
1789
1790
1791 LTTV_MODULE("filter", "Filters traceset and events", \
1792 "Filters traceset and events specifically to user input", \
1793 module_init, module_destroy)
1794
1795
1796
This page took 0.06536 seconds and 4 git commands to generate.