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