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
= { NULL
}; /* init to NULL for gcc */
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 res
= fscanf(fp
, "<ATTRS>");
493 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
495 name
= g_quark_from_string(buffer
);
496 if(strcmp(type
, "ATTRS") == 0) {
497 res
= fscanf(fp
, ">");
499 subtree
= lttv_attribute_find_subdir(self
, name
);
500 lttv_attribute_read_xml(subtree
, fp
);
502 else if(strcmp(type
, "INT") == 0) {
503 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
504 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
507 else if(strcmp(type
, "UINT") == 0) {
508 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
509 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
512 else if(strcmp(type
, "LONG") == 0) {
513 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
514 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
517 else if(strcmp(type
, "ULONG") == 0) {
518 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
519 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
522 else if(strcmp(type
, "FLOAT") == 0) {
524 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
525 res
= fscanf(fp
, " VALUE=%f/>", &d
);
526 *(value
.v_float
) = d
;
529 else if(strcmp(type
, "DOUBLE") == 0) {
530 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
531 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
534 else if(strcmp(type
, "TIME") == 0) {
535 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
536 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
537 &(value
.v_time
->tv_nsec
));
540 else if(strcmp(type
, "POINTER") == 0) {
541 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
542 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
543 g_error("Cannot read a pointer");
545 else if(strcmp(type
, "STRING") == 0) {
546 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
547 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
548 *(value
.v_string
) = g_strdup(buffer
);
551 else if(strcmp(type
, "GOBJECT") == 0) {
552 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
553 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
554 g_error("Cannot read a pointer");
556 else if(strcmp(type
, "NONE") == 0) {
557 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
558 res
= fscanf(fp
, "/>");
561 else g_error("Unknown type to read");
563 res
= fscanf(fp
, "</ATTRS>");
567 static LttvAttribute
*
568 new_attribute (LttvAttribute
*self
)
570 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
575 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
577 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
579 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
582 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
583 lttv_attribute_get_number
;
585 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
586 lttv_attribute_named
;
588 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
589 LttvAttributeName
*name
, LttvAttributeValue
*v
, gboolean
*is_named
))
592 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
593 LttvAttributeName name
, LttvAttributeValue
*v
))
594 lttv_attribute_get_by_name
;
596 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
597 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
599 klass
->add_unnamed
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
600 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add_unnamed
;
602 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
603 lttv_attribute_remove
;
605 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
606 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
608 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
609 LttvAttributeName name
)) lttv_attribute_find_subdir
;
611 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
612 LttvAttributeName name
)) lttv_attribute_find_subdir_unnamed
;
616 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
618 LttvAttribute
*self
= (LttvAttribute
*)instance
;
619 self
->names
= g_hash_table_new(g_direct_hash
,
621 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
626 attribute_finalize (LttvAttribute
*self
)
629 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
631 for(i
=0;i
<self
->attributes
->len
;i
++) {
632 lttv_attribute_remove(self
, i
);
635 g_hash_table_destroy(self
->names
);
636 g_array_free(self
->attributes
, TRUE
);
641 attribute_class_init (LttvAttributeClass
*klass
)
643 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
645 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
649 lttv_attribute_get_type (void)
651 static GType type
= 0;
653 static const GTypeInfo info
= {
654 sizeof (LttvAttributeClass
),
655 NULL
, /* base_init */
656 NULL
, /* base_finalize */
657 (GClassInitFunc
) attribute_class_init
, /* class_init */
658 NULL
, /* class_finalize */
659 NULL
, /* class_data */
660 sizeof (LttvAttribute
),
662 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
663 NULL
/* value handling */
666 static const GInterfaceInfo iattribute_info
= {
667 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
668 NULL
, /* interface_finalize */
669 NULL
/* interface_data */
672 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
674 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);