1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
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;
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.
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,
24 #include <lttv/attribute.h>
26 #include <ltt/compiler.h>
28 typedef union _AttributeValue
{
32 unsigned long dv_ulong
;
42 typedef struct _Attribute
{
43 LttvAttributeName name
;
44 LttvAttributeType type
;
50 static __inline__ LttvAttributeValue
51 address_of_value(LttvAttributeType t
, AttributeValue
*v
)
53 LttvAttributeValue va
;
56 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
57 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
58 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
59 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
60 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
61 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
62 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
63 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
64 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
65 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
66 case LTTV_NONE
: break;
73 init_value(LttvAttributeType t
)
78 case LTTV_INT
: v
.dv_int
= 0; break;
79 case LTTV_UINT
: v
.dv_uint
= 0; break;
80 case LTTV_LONG
: v
.dv_long
= 0; break;
81 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
82 case LTTV_FLOAT
: v
.dv_float
= 0; break;
83 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
84 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
85 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
86 case LTTV_STRING
: v
.dv_string
= NULL
; break;
87 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
88 case LTTV_NONE
: break;
95 lttv_attribute_get_number(LttvAttribute
*self
)
97 return self
->attributes
->len
;
101 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
103 *homogeneous
= FALSE
;
108 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
109 LttvAttributeValue
*v
, gboolean
*is_named
)
113 a
= &g_array_index(self
->attributes
, Attribute
, i
);
115 *v
= address_of_value(a
->type
, &(a
->value
));
116 *is_named
= a
->is_named
;
122 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
123 LttvAttributeValue
*v
)
131 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
132 if(p
== NULL
) return LTTV_NONE
;
134 i
= GPOINTER_TO_UINT(p
);
136 a
= &g_array_index(self
->attributes
, Attribute
, i
);
137 *v
= address_of_value(a
->type
, &(a
->value
));
143 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
150 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
151 if(i
!= 0) g_error("duplicate entry in attribute table");
156 a
.value
= init_value(t
);
157 g_array_append_val(self
->attributes
, a
);
158 i
= self
->attributes
->len
- 1;
159 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
160 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
161 GUINT_TO_POINTER(i
+ 1));
162 return address_of_value(t
, &(pa
->value
));
166 lttv_attribute_add_unnamed(LttvAttribute
*self
, LttvAttributeName name
,
173 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
174 if(i
!= 0) g_error("duplicate entry in attribute table");
179 a
.value
= init_value(t
);
180 g_array_append_val(self
->attributes
, a
);
181 i
= self
->attributes
->len
- 1;
182 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
183 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
184 GUINT_TO_POINTER(i
+ 1));
185 return address_of_value(t
, &(pa
->value
));
189 /* Remove an attribute */
192 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
196 a
= &g_array_index(self
->attributes
, Attribute
, i
);
198 /* If the element is a gobject, unreference it. */
199 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
200 g_object_unref(a
->value
.dv_gobject
);
202 /* Remove the array element and its entry in the name index */
204 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
205 g_array_remove_index_fast(self
->attributes
, i
);
207 /* The element used to replace the removed element has its index entry
208 all wrong now. Reinsert it with its new position. */
210 if(likely(self
->attributes
->len
!= i
)){
211 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
212 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
217 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
221 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
222 if(unlikely(i
== 0)) g_error("remove by name non existent attribute");
224 lttv_attribute_remove(self
, i
- 1);
227 /* Create an empty iattribute object and add it as an attribute under the
228 specified name, or return an existing iattribute attribute. If an
229 attribute of that name already exists but is not a GObject supporting the
230 iattribute interface, return NULL. */
232 /*CHECK*/LttvAttribute
*
233 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
241 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
243 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
244 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
245 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
249 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
250 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
251 return (LttvAttribute
*)new;
254 /*CHECK*/LttvAttribute
*
255 lttv_attribute_find_subdir_unnamed(LttvAttribute
*self
, LttvAttributeName name
)
263 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
265 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
266 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
267 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
271 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
272 *(lttv_attribute_add_unnamed(self
, name
, LTTV_GOBJECT
).v_gobject
)
274 return (LttvAttribute
*)new;
278 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
279 LttvAttributeType t
, LttvAttributeValue
*v
)
285 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
287 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
288 if(unlikely(a
->type
!= t
)) return FALSE
;
289 *v
= address_of_value(t
, &(a
->value
));
293 *v
= lttv_attribute_add(self
, name
, t
);
298 lttv_attribute_find_unnamed(LttvAttribute
*self
, LttvAttributeName name
,
299 LttvAttributeType t
, LttvAttributeValue
*v
)
305 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
307 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
308 if(unlikely(a
->type
!= t
)) return FALSE
;
309 *v
= address_of_value(t
, &(a
->value
));
313 *v
= lttv_attribute_add_unnamed(self
, name
, t
);
318 /*void lttv_attribute_recursive_free(LttvAttribute *self)
324 nb = self->attributes->len;
326 for(i = 0 ; i < nb ; i++) {
327 a = &g_array_index(self->attributes, Attribute, i);
328 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
329 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
332 g_object_unref(self);
337 lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
343 LttvAttributeValue value
;
346 nb
= src
->attributes
->len
;
348 for(i
= 0 ; i
< nb
; i
++) {
349 a
= &g_array_index(src
->attributes
, Attribute
, i
);
350 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
352 lttv_attribute_recursive_add(
353 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
354 (LttvAttribute
*)(a
->value
.dv_gobject
));
356 lttv_attribute_recursive_add(
357 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir_unnamed(
358 dest
, a
->name
), (LttvAttribute
*)(a
->value
.dv_gobject
));
362 retval
= lttv_attribute_find(dest
, a
->name
, a
->type
, &value
);
366 retval
= lttv_attribute_find_unnamed(dest
, a
->name
, a
->type
, &value
);
371 *value
.v_int
+= a
->value
.dv_int
;
374 *value
.v_uint
+= a
->value
.dv_uint
;
377 *value
.v_long
+= a
->value
.dv_long
;
380 *value
.v_ulong
+= a
->value
.dv_ulong
;
383 *value
.v_float
+= a
->value
.dv_float
;
386 *value
.v_double
+= a
->value
.dv_double
;
389 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
406 print_indent(FILE *fp
, int pos
)
410 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
415 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
421 nb
= self
->attributes
->len
;
423 fprintf(fp
,"<ATTRS>\n");
424 for(i
= 0 ; i
< nb
; i
++) {
425 a
= &g_array_index(self
->attributes
, Attribute
, i
);
426 print_indent(fp
, pos
);
427 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
428 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
429 fprintf(fp
, "TYPE=ATTRS>");
430 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
431 pos
+ indent
, indent
);
436 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
439 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
442 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
445 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
448 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
451 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
454 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n",
455 a
->value
.dv_time
.tv_sec
, a
->value
.dv_time
.tv_nsec
);
458 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
461 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
464 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
467 fprintf(fp
, "TYPE=NONE/>\n");
472 print_indent(fp
, pos
);
473 fprintf(fp
,"</ATTRS>\n");
478 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
482 char buffer
[256], type
[10];
484 LttvAttributeName name
;
486 LttvAttributeValue value
;
488 LttvAttribute
*subtree
;
490 fscanf(fp
,"<ATTRS>");
492 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
494 name
= g_quark_from_string(buffer
);
495 if(strcmp(type
, "ATTRS") == 0) {
497 subtree
= lttv_attribute_find_subdir(self
, name
);
498 lttv_attribute_read_xml(subtree
, fp
);
500 else if(strcmp(type
, "INT") == 0) {
501 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
502 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
505 else if(strcmp(type
, "UINT") == 0) {
506 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
507 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
510 else if(strcmp(type
, "LONG") == 0) {
511 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
512 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
515 else if(strcmp(type
, "ULONG") == 0) {
516 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
517 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
520 else if(strcmp(type
, "FLOAT") == 0) {
522 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
523 res
= fscanf(fp
, " VALUE=%f/>", &d
);
524 *(value
.v_float
) = d
;
527 else if(strcmp(type
, "DOUBLE") == 0) {
528 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
529 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
532 else if(strcmp(type
, "TIME") == 0) {
533 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
534 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
535 &(value
.v_time
->tv_nsec
));
538 else if(strcmp(type
, "POINTER") == 0) {
539 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
540 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
541 g_error("Cannot read a pointer");
543 else if(strcmp(type
, "STRING") == 0) {
544 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
545 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
546 *(value
.v_string
) = g_strdup(buffer
);
549 else if(strcmp(type
, "GOBJECT") == 0) {
550 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
551 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
552 g_error("Cannot read a pointer");
554 else if(strcmp(type
, "NONE") == 0) {
555 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
558 else g_error("Unknown type to read");
560 fscanf(fp
,"</ATTRS>");
563 static LttvAttribute
*
564 new_attribute (LttvAttribute
*self
)
566 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
571 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
573 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
575 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
578 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
579 lttv_attribute_get_number
;
581 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
582 lttv_attribute_named
;
584 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
585 LttvAttributeName
*name
, LttvAttributeValue
*v
, gboolean
*is_named
))
588 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
589 LttvAttributeName name
, LttvAttributeValue
*v
))
590 lttv_attribute_get_by_name
;
592 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
593 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
595 klass
->add_unnamed
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
596 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add_unnamed
;
598 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
599 lttv_attribute_remove
;
601 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
602 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
604 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
605 LttvAttributeName name
)) lttv_attribute_find_subdir
;
607 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
608 LttvAttributeName name
)) lttv_attribute_find_subdir_unnamed
;
612 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
614 LttvAttribute
*self
= (LttvAttribute
*)instance
;
615 self
->names
= g_hash_table_new(g_direct_hash
,
617 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
622 attribute_finalize (LttvAttribute
*self
)
625 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
627 for(i
=0;i
<self
->attributes
->len
;i
++) {
628 lttv_attribute_remove(self
, i
);
631 g_hash_table_destroy(self
->names
);
632 g_array_free(self
->attributes
, TRUE
);
637 attribute_class_init (LttvAttributeClass
*klass
)
639 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
641 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
645 lttv_attribute_get_type (void)
647 static GType type
= 0;
649 static const GTypeInfo info
= {
650 sizeof (LttvAttributeClass
),
651 NULL
, /* base_init */
652 NULL
, /* base_finalize */
653 (GClassInitFunc
) attribute_class_init
, /* class_init */
654 NULL
, /* class_finalize */
655 NULL
, /* class_data */
656 sizeof (LttvAttribute
),
658 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
659 NULL
/* value handling */
662 static const GInterfaceInfo iattribute_info
= {
663 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
664 NULL
, /* interface_finalize */
665 NULL
/* interface_data */
668 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
670 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);