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