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>
25 #include <lttv/compiler.h>
27 typedef union _AttributeValue
{
31 unsigned long dv_ulong
;
41 typedef struct _Attribute
{
42 LttvAttributeName name
;
43 LttvAttributeType type
;
49 static __inline__ LttvAttributeValue
50 address_of_value(LttvAttributeType t
, AttributeValue
*v
)
52 LttvAttributeValue va
= { NULL
}; /* init to NULL for gcc */
55 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
56 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
57 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
58 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
59 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
60 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
61 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
62 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
63 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
64 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
65 case LTTV_NONE
: break;
72 init_value(LttvAttributeType t
)
77 case LTTV_INT
: v
.dv_int
= 0; break;
78 case LTTV_UINT
: v
.dv_uint
= 0; break;
79 case LTTV_LONG
: v
.dv_long
= 0; break;
80 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
81 case LTTV_FLOAT
: v
.dv_float
= 0; break;
82 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
83 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
84 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
85 case LTTV_STRING
: v
.dv_string
= NULL
; break;
86 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
87 case LTTV_NONE
: break;
94 lttv_attribute_get_number(LttvAttribute
*self
)
96 return self
->attributes
->len
;
100 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
102 *homogeneous
= FALSE
;
107 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
108 LttvAttributeValue
*v
, gboolean
*is_named
)
112 a
= &g_array_index(self
->attributes
, Attribute
, i
);
114 *v
= address_of_value(a
->type
, &(a
->value
));
115 *is_named
= a
->is_named
;
121 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
122 LttvAttributeValue
*v
)
130 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
131 if(p
== NULL
) return LTTV_NONE
;
133 i
= GPOINTER_TO_UINT(p
);
135 a
= &g_array_index(self
->attributes
, Attribute
, i
);
136 *v
= address_of_value(a
->type
, &(a
->value
));
142 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
149 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
150 if(i
!= 0) g_error("duplicate entry in attribute table");
155 a
.value
= init_value(t
);
156 g_array_append_val(self
->attributes
, a
);
157 i
= self
->attributes
->len
- 1;
158 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
159 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
160 GUINT_TO_POINTER(i
+ 1));
161 return address_of_value(t
, &(pa
->value
));
165 lttv_attribute_add_unnamed(LttvAttribute
*self
, LttvAttributeName name
,
172 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
173 if(i
!= 0) g_error("duplicate entry in attribute table");
178 a
.value
= init_value(t
);
179 g_array_append_val(self
->attributes
, a
);
180 i
= self
->attributes
->len
- 1;
181 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
182 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
183 GUINT_TO_POINTER(i
+ 1));
184 return address_of_value(t
, &(pa
->value
));
188 /* Remove an attribute */
191 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
195 a
= &g_array_index(self
->attributes
, Attribute
, i
);
197 /* If the element is a gobject, unreference it. */
198 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
199 g_object_unref(a
->value
.dv_gobject
);
201 /* Remove the array element and its entry in the name index */
203 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
204 g_array_remove_index_fast(self
->attributes
, i
);
206 /* The element used to replace the removed element has its index entry
207 all wrong now. Reinsert it with its new position. */
209 if(likely(self
->attributes
->len
!= i
)){
210 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
211 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
216 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
220 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
221 if(unlikely(i
== 0)) g_error("remove by name non existent attribute");
223 lttv_attribute_remove(self
, i
- 1);
226 /* Create an empty iattribute object and add it as an attribute under the
227 specified name, or return an existing iattribute attribute. If an
228 attribute of that name already exists but is not a GObject supporting the
229 iattribute interface, return NULL. */
231 /*CHECK*/LttvAttribute
*
232 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
240 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
242 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
243 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
244 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
248 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
249 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
250 return (LttvAttribute
*)new;
253 /*CHECK*/LttvAttribute
*
254 lttv_attribute_find_subdir_unnamed(LttvAttribute
*self
, LttvAttributeName name
)
262 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
264 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
265 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
266 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
270 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
271 *(lttv_attribute_add_unnamed(self
, name
, LTTV_GOBJECT
).v_gobject
)
273 return (LttvAttribute
*)new;
277 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
278 LttvAttributeType t
, LttvAttributeValue
*v
)
284 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
286 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
287 if(unlikely(a
->type
!= t
)) return FALSE
;
288 *v
= address_of_value(t
, &(a
->value
));
292 *v
= lttv_attribute_add(self
, name
, t
);
297 lttv_attribute_find_unnamed(LttvAttribute
*self
, LttvAttributeName name
,
298 LttvAttributeType t
, LttvAttributeValue
*v
)
304 i
= GPOINTER_TO_UINT(g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
)));
306 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
307 if(unlikely(a
->type
!= t
)) return FALSE
;
308 *v
= address_of_value(t
, &(a
->value
));
312 *v
= lttv_attribute_add_unnamed(self
, name
, t
);
317 /*void lttv_attribute_recursive_free(LttvAttribute *self)
323 nb = self->attributes->len;
325 for(i = 0 ; i < nb ; i++) {
326 a = &g_array_index(self->attributes, Attribute, i);
327 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
328 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
331 g_object_unref(self);
336 lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
342 LttvAttributeValue value
;
345 nb
= src
->attributes
->len
;
347 for(i
= 0 ; i
< nb
; i
++) {
348 a
= &g_array_index(src
->attributes
, Attribute
, i
);
349 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
351 lttv_attribute_recursive_add(
352 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
353 (LttvAttribute
*)(a
->value
.dv_gobject
));
355 lttv_attribute_recursive_add(
356 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir_unnamed(
357 dest
, a
->name
), (LttvAttribute
*)(a
->value
.dv_gobject
));
361 retval
= lttv_attribute_find(dest
, a
->name
, a
->type
, &value
);
365 retval
= lttv_attribute_find_unnamed(dest
, a
->name
, a
->type
, &value
);
370 *value
.v_int
+= a
->value
.dv_int
;
373 *value
.v_uint
+= a
->value
.dv_uint
;
376 *value
.v_long
+= a
->value
.dv_long
;
379 *value
.v_ulong
+= a
->value
.dv_ulong
;
382 *value
.v_float
+= a
->value
.dv_float
;
385 *value
.v_double
+= a
->value
.dv_double
;
388 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
405 print_indent(FILE *fp
, int pos
)
409 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
414 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
420 nb
= self
->attributes
->len
;
422 fprintf(fp
,"<ATTRS>\n");
423 for(i
= 0 ; i
< nb
; i
++) {
424 a
= &g_array_index(self
->attributes
, Attribute
, i
);
425 print_indent(fp
, pos
);
426 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
427 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
428 fprintf(fp
, "TYPE=ATTRS>");
429 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
430 pos
+ indent
, indent
);
435 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
438 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
441 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
444 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
447 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
450 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
453 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n",
454 a
->value
.dv_time
.tv_sec
, a
->value
.dv_time
.tv_nsec
);
457 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
460 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
463 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
466 fprintf(fp
, "TYPE=NONE/>\n");
471 print_indent(fp
, pos
);
472 fprintf(fp
,"</ATTRS>\n");
477 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
481 char buffer
[256], type
[10];
483 LttvAttributeName name
;
485 LttvAttributeValue value
;
487 LttvAttribute
*subtree
;
489 res
= 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) {
496 res
= fscanf(fp
, ">");
498 subtree
= lttv_attribute_find_subdir(self
, name
);
499 lttv_attribute_read_xml(subtree
, fp
);
501 else if(strcmp(type
, "INT") == 0) {
502 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
503 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
506 else if(strcmp(type
, "UINT") == 0) {
507 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
508 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
511 else if(strcmp(type
, "LONG") == 0) {
512 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
513 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
516 else if(strcmp(type
, "ULONG") == 0) {
517 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
518 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
521 else if(strcmp(type
, "FLOAT") == 0) {
523 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
524 res
= fscanf(fp
, " VALUE=%f/>", &d
);
525 *(value
.v_float
) = d
;
528 else if(strcmp(type
, "DOUBLE") == 0) {
529 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
530 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
533 else if(strcmp(type
, "TIME") == 0) {
534 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
535 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
536 &(value
.v_time
->tv_nsec
));
539 else if(strcmp(type
, "POINTER") == 0) {
540 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
541 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
542 g_error("Cannot read a pointer");
544 else if(strcmp(type
, "STRING") == 0) {
545 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
546 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
547 *(value
.v_string
) = g_strdup(buffer
);
550 else if(strcmp(type
, "GOBJECT") == 0) {
551 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
552 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
553 g_error("Cannot read a pointer");
555 else if(strcmp(type
, "NONE") == 0) {
556 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
557 res
= fscanf(fp
, "/>");
560 else g_error("Unknown type to read");
562 res
= fscanf(fp
, "</ATTRS>");
566 static LttvAttribute
*
567 new_attribute (LttvAttribute
*self
)
569 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
574 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
576 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
578 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
581 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
582 lttv_attribute_get_number
;
584 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
585 lttv_attribute_named
;
587 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
588 LttvAttributeName
*name
, LttvAttributeValue
*v
, gboolean
*is_named
))
591 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
592 LttvAttributeName name
, LttvAttributeValue
*v
))
593 lttv_attribute_get_by_name
;
595 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
596 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
598 klass
->add_unnamed
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
599 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add_unnamed
;
601 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
602 lttv_attribute_remove
;
604 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
605 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
607 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
608 LttvAttributeName name
)) lttv_attribute_find_subdir
;
610 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
611 LttvAttributeName name
)) lttv_attribute_find_subdir_unnamed
;
615 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
617 LttvAttribute
*self
= (LttvAttribute
*)instance
;
618 self
->names
= g_hash_table_new(g_direct_hash
,
620 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
625 attribute_finalize (LttvAttribute
*self
)
628 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
630 for(i
=0;i
<self
->attributes
->len
;i
++) {
631 lttv_attribute_remove(self
, i
);
634 g_hash_table_destroy(self
->names
);
635 g_array_free(self
->attributes
, TRUE
);
640 attribute_class_init (LttvAttributeClass
*klass
)
642 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
644 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
648 lttv_attribute_get_type (void)
650 static GType type
= 0;
652 static const GTypeInfo info
= {
653 sizeof (LttvAttributeClass
),
654 NULL
, /* base_init */
655 NULL
, /* base_finalize */
656 (GClassInitFunc
) attribute_class_init
, /* class_init */
657 NULL
, /* class_finalize */
658 NULL
, /* class_data */
659 sizeof (LttvAttribute
),
661 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
662 NULL
/* value handling */
665 static const GInterfaceInfo iattribute_info
= {
666 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
667 NULL
, /* interface_finalize */
668 NULL
/* interface_data */
671 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
673 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);