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
= 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);
335 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
341 LttvAttributeValue value
;
344 nb
= src
->attributes
->len
;
346 for(i
= 0 ; i
< nb
; i
++) {
347 a
= &g_array_index(src
->attributes
, Attribute
, i
);
348 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
350 lttv_attribute_recursive_add(
351 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
352 (LttvAttribute
*)(a
->value
.dv_gobject
));
354 lttv_attribute_recursive_add(
355 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir_unnamed(
356 dest
, a
->name
), (LttvAttribute
*)(a
->value
.dv_gobject
));
360 retval
= lttv_attribute_find(dest
, a
->name
, a
->type
, &value
);
364 retval
= lttv_attribute_find_unnamed(dest
, a
->name
, a
->type
, &value
);
369 *value
.v_int
+= a
->value
.dv_int
;
372 *value
.v_uint
+= a
->value
.dv_uint
;
375 *value
.v_long
+= a
->value
.dv_long
;
378 *value
.v_ulong
+= a
->value
.dv_ulong
;
381 *value
.v_float
+= a
->value
.dv_float
;
384 *value
.v_double
+= a
->value
.dv_double
;
387 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
404 print_indent(FILE *fp
, int pos
)
408 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
413 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
419 nb
= self
->attributes
->len
;
421 fprintf(fp
,"<ATTRS>\n");
422 for(i
= 0 ; i
< nb
; i
++) {
423 a
= &g_array_index(self
->attributes
, Attribute
, i
);
424 print_indent(fp
, pos
);
425 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
426 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
427 fprintf(fp
, "TYPE=ATTRS>");
428 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
429 pos
+ indent
, indent
);
434 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
437 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
440 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
443 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
446 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
449 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
452 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
453 a
->value
.dv_time
.tv_nsec
);
456 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
459 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
462 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
465 fprintf(fp
, "TYPE=NONE/>\n");
470 print_indent(fp
, pos
);
471 fprintf(fp
,"</ATTRS>\n");
476 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
480 char buffer
[256], type
[10];
482 LttvAttributeName name
;
484 LttvAttributeValue value
;
486 LttvAttribute
*subtree
;
488 fscanf(fp
,"<ATTRS>");
490 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
492 name
= g_quark_from_string(buffer
);
493 if(strcmp(type
, "ATTRS") == 0) {
495 subtree
= lttv_attribute_find_subdir(self
, name
);
496 lttv_attribute_read_xml(subtree
, fp
);
498 else if(strcmp(type
, "INT") == 0) {
499 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
500 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
503 else if(strcmp(type
, "UINT") == 0) {
504 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
505 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
508 else if(strcmp(type
, "LONG") == 0) {
509 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
510 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
513 else if(strcmp(type
, "ULONG") == 0) {
514 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
515 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
518 else if(strcmp(type
, "FLOAT") == 0) {
520 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
521 res
= fscanf(fp
, " VALUE=%f/>", &d
);
522 *(value
.v_float
) = d
;
525 else if(strcmp(type
, "DOUBLE") == 0) {
526 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
527 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
530 else if(strcmp(type
, "TIME") == 0) {
531 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
532 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
533 &(value
.v_time
->tv_nsec
));
536 else if(strcmp(type
, "POINTER") == 0) {
537 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
538 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
539 g_error("Cannot read a pointer");
541 else if(strcmp(type
, "STRING") == 0) {
542 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
543 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
544 *(value
.v_string
) = g_strdup(buffer
);
547 else if(strcmp(type
, "GOBJECT") == 0) {
548 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
549 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
550 g_error("Cannot read a pointer");
552 else if(strcmp(type
, "NONE") == 0) {
553 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
556 else g_error("Unknown type to read");
558 fscanf(fp
,"</ATTRS>");
561 static LttvAttribute
*
562 new_attribute (LttvAttribute
*self
)
564 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
569 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
571 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
573 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
576 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
577 lttv_attribute_get_number
;
579 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
580 lttv_attribute_named
;
582 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
583 LttvAttributeName
*name
, LttvAttributeValue
*v
, gboolean
*is_named
))
586 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
587 LttvAttributeName name
, LttvAttributeValue
*v
))
588 lttv_attribute_get_by_name
;
590 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
591 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
593 klass
->add_unnamed
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
594 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add_unnamed
;
596 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
597 lttv_attribute_remove
;
599 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
600 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
602 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
603 LttvAttributeName name
)) lttv_attribute_find_subdir
;
605 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
606 LttvAttributeName name
)) lttv_attribute_find_subdir_unnamed
;
610 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
612 LttvAttribute
*self
= (LttvAttribute
*)instance
;
613 self
->names
= g_hash_table_new(g_direct_hash
,
615 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
620 attribute_finalize (LttvAttribute
*self
)
623 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
625 for(i
=0;i
<self
->attributes
->len
;i
++) {
626 lttv_attribute_remove(self
, i
);
629 g_hash_table_destroy(self
->names
);
630 g_array_free(self
->attributes
, TRUE
);
635 attribute_class_init (LttvAttributeClass
*klass
)
637 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
639 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
643 lttv_attribute_get_type (void)
645 static GType type
= 0;
647 static const GTypeInfo info
= {
648 sizeof (LttvAttributeClass
),
649 NULL
, /* base_init */
650 NULL
, /* base_finalize */
651 (GClassInitFunc
) attribute_class_init
, /* class_init */
652 NULL
, /* class_finalize */
653 NULL
, /* class_data */
654 sizeof (LttvAttribute
),
656 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
657 NULL
/* value handling */
660 static const GInterfaceInfo iattribute_info
= {
661 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
662 NULL
, /* interface_finalize */
663 NULL
/* interface_data */
666 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
668 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);