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
address_of_value(LttvAttributeType t
,
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;
72 AttributeValue
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
= (unsigned)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
= (unsigned)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
= (unsigned)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
= (unsigned)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
= (unsigned)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
= (unsigned)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
= (unsigned)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);
335 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
341 LttvAttributeValue value
;
343 nb
= src
->attributes
->len
;
345 for(i
= 0 ; i
< nb
; i
++) {
346 a
= &g_array_index(src
->attributes
, Attribute
, i
);
347 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
349 lttv_attribute_recursive_add(
350 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
351 (LttvAttribute
*)(a
->value
.dv_gobject
));
353 lttv_attribute_recursive_add(
354 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir_unnamed(
355 dest
, a
->name
), (LttvAttribute
*)(a
->value
.dv_gobject
));
359 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
361 g_assert(lttv_attribute_find_unnamed(dest
, a
->name
, a
->type
, &value
));
364 *value
.v_int
+= a
->value
.dv_int
;
367 *value
.v_uint
+= a
->value
.dv_uint
;
370 *value
.v_long
+= a
->value
.dv_long
;
373 *value
.v_ulong
+= a
->value
.dv_ulong
;
376 *value
.v_float
+= a
->value
.dv_float
;
379 *value
.v_double
+= a
->value
.dv_double
;
382 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
399 print_indent(FILE *fp
, int pos
)
403 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
408 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
414 nb
= self
->attributes
->len
;
416 fprintf(fp
,"<ATTRS>\n");
417 for(i
= 0 ; i
< nb
; i
++) {
418 a
= &g_array_index(self
->attributes
, Attribute
, i
);
419 print_indent(fp
, pos
);
420 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
421 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
422 fprintf(fp
, "TYPE=ATTRS>");
423 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
424 pos
+ indent
, indent
);
429 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
432 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
435 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
438 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
441 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
444 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
447 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
448 a
->value
.dv_time
.tv_nsec
);
451 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
454 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
457 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
460 fprintf(fp
, "TYPE=NONE/>\n");
465 print_indent(fp
, pos
);
466 fprintf(fp
,"</ATTRS>\n");
471 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
475 char buffer
[256], type
[10];
477 LttvAttributeName name
;
479 LttvAttributeValue value
;
481 LttvAttribute
*subtree
;
483 fscanf(fp
,"<ATTRS>");
485 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
487 name
= g_quark_from_string(buffer
);
488 if(strcmp(type
, "ATTRS") == 0) {
490 subtree
= lttv_attribute_find_subdir(self
, name
);
491 lttv_attribute_read_xml(subtree
, fp
);
493 else if(strcmp(type
, "INT") == 0) {
494 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
495 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
498 else if(strcmp(type
, "UINT") == 0) {
499 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
500 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
503 else if(strcmp(type
, "LONG") == 0) {
504 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
505 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
508 else if(strcmp(type
, "ULONG") == 0) {
509 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
510 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
513 else if(strcmp(type
, "FLOAT") == 0) {
515 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
516 res
= fscanf(fp
, " VALUE=%f/>", &d
);
517 *(value
.v_float
) = d
;
520 else if(strcmp(type
, "DOUBLE") == 0) {
521 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
522 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
525 else if(strcmp(type
, "TIME") == 0) {
526 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
527 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
528 &(value
.v_time
->tv_nsec
));
531 else if(strcmp(type
, "POINTER") == 0) {
532 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
533 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
534 g_error("Cannot read a pointer");
536 else if(strcmp(type
, "STRING") == 0) {
537 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
538 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
539 *(value
.v_string
) = g_strdup(buffer
);
542 else if(strcmp(type
, "GOBJECT") == 0) {
543 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
544 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
545 g_error("Cannot read a pointer");
547 else if(strcmp(type
, "NONE") == 0) {
548 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
551 else g_error("Unknown type to read");
553 fscanf(fp
,"</ATTRS>");
556 static LttvAttribute
*
557 new_attribute (LttvAttribute
*self
)
559 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
564 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
566 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
568 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
571 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
572 lttv_attribute_get_number
;
574 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
575 lttv_attribute_named
;
577 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
578 LttvAttributeName
*name
, LttvAttributeValue
*v
, gboolean
*is_named
))
581 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
582 LttvAttributeName name
, LttvAttributeValue
*v
))
583 lttv_attribute_get_by_name
;
585 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
586 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
588 klass
->add_unnamed
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
589 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add_unnamed
;
591 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
592 lttv_attribute_remove
;
594 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
595 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
597 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
598 LttvAttributeName name
)) lttv_attribute_find_subdir
;
600 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
601 LttvAttributeName name
)) lttv_attribute_find_subdir_unnamed
;
605 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
607 LttvAttribute
*self
= (LttvAttribute
*)instance
;
608 self
->names
= g_hash_table_new(g_direct_hash
,
610 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
615 attribute_finalize (LttvAttribute
*self
)
618 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
620 for(i
=0;i
<self
->attributes
->len
;i
++) {
621 lttv_attribute_remove(self
, i
);
624 g_hash_table_destroy(self
->names
);
625 g_array_free(self
->attributes
, TRUE
);
630 attribute_class_init (LttvAttributeClass
*klass
)
632 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
634 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
638 lttv_attribute_get_type (void)
640 static GType type
= 0;
642 static const GTypeInfo info
= {
643 sizeof (LttvAttributeClass
),
644 NULL
, /* base_init */
645 NULL
, /* base_finalize */
646 (GClassInitFunc
) attribute_class_init
, /* class_init */
647 NULL
, /* class_finalize */
648 NULL
, /* class_data */
649 sizeof (LttvAttribute
),
651 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
652 NULL
/* value handling */
655 static const GInterfaceInfo iattribute_info
= {
656 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
657 NULL
, /* interface_finalize */
658 NULL
/* interface_data */
661 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
663 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);