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
;
49 static __inline__ LttvAttributeValue
address_of_value(LttvAttributeType t
,
52 LttvAttributeValue va
;
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;
71 AttributeValue
init_value(LttvAttributeType t
)
76 case LTTV_INT
: v
.dv_int
= 0; break;
77 case LTTV_UINT
: v
.dv_uint
= 0; break;
78 case LTTV_LONG
: v
.dv_long
= 0; break;
79 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
80 case LTTV_FLOAT
: v
.dv_float
= 0; break;
81 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
82 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
83 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
84 case LTTV_STRING
: v
.dv_string
= NULL
; break;
85 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
86 case LTTV_NONE
: break;
93 lttv_attribute_get_number(LttvAttribute
*self
)
95 return self
->attributes
->len
;
100 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
102 *homogeneous
= FALSE
;
108 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
109 LttvAttributeValue
*v
)
113 a
= &g_array_index(self
->attributes
, Attribute
, i
);
115 *v
= address_of_value(a
->type
, &(a
->value
));
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");
154 a
.value
= init_value(t
);
155 g_array_append_val(self
->attributes
, a
);
156 i
= self
->attributes
->len
- 1;
157 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
158 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
159 GUINT_TO_POINTER(i
+ 1));
160 return address_of_value(t
, &(pa
->value
));
164 /* Remove an attribute */
167 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
171 a
= &g_array_index(self
->attributes
, Attribute
, i
);
173 /* If the element is a gobject, unreference it. */
174 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
175 g_object_unref(a
->value
.dv_gobject
);
177 /* Remove the array element and its entry in the name index */
179 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
180 g_array_remove_index_fast(self
->attributes
, i
);
182 /* The element used to replace the removed element has its index entry
183 all wrong now. Reinsert it with its new position. */
185 if(likely(self
->attributes
->len
!= i
)){
186 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
187 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
192 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
196 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
197 if(unlikely(i
== 0)) g_error("remove by name non existent attribute");
199 lttv_attribute_remove(self
, i
- 1);
202 /* Create an empty iattribute object and add it as an attribute under the
203 specified name, or return an existing iattribute attribute. If an
204 attribute of that name already exists but is not a GObject supporting the
205 iattribute interface, return NULL. */
207 /*CHECK*/LttvAttribute
*
208 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
216 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
218 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
219 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
220 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
224 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
225 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
226 return (LttvAttribute
*)new;
230 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
231 LttvAttributeType t
, LttvAttributeValue
*v
)
237 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
239 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
240 if(unlikely(a
->type
!= t
)) return FALSE
;
241 *v
= address_of_value(t
, &(a
->value
));
245 *v
= lttv_attribute_add(self
, name
, t
);
250 /*void lttv_attribute_recursive_free(LttvAttribute *self)
256 nb = self->attributes->len;
258 for(i = 0 ; i < nb ; i++) {
259 a = &g_array_index(self->attributes, Attribute, i);
260 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
261 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
264 g_object_unref(self);
268 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
274 LttvAttributeValue value
;
276 nb
= src
->attributes
->len
;
278 for(i
= 0 ; i
< nb
; i
++) {
279 a
= &g_array_index(src
->attributes
, Attribute
, i
);
280 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
281 lttv_attribute_recursive_add(
282 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
283 (LttvAttribute
*)(a
->value
.dv_gobject
));
286 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
289 *value
.v_int
+= a
->value
.dv_int
;
292 *value
.v_uint
+= a
->value
.dv_uint
;
295 *value
.v_long
+= a
->value
.dv_long
;
298 *value
.v_ulong
+= a
->value
.dv_ulong
;
301 *value
.v_float
+= a
->value
.dv_float
;
304 *value
.v_double
+= a
->value
.dv_double
;
307 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
324 print_indent(FILE *fp
, int pos
)
328 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
333 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
339 nb
= self
->attributes
->len
;
341 fprintf(fp
,"<ATTRS>\n");
342 for(i
= 0 ; i
< nb
; i
++) {
343 a
= &g_array_index(self
->attributes
, Attribute
, i
);
344 print_indent(fp
, pos
);
345 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
346 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
347 fprintf(fp
, "TYPE=ATTRS>");
348 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
349 pos
+ indent
, indent
);
354 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
357 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
360 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
363 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
366 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
369 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
372 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
373 a
->value
.dv_time
.tv_nsec
);
376 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
379 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
382 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
385 fprintf(fp
, "TYPE=NONE/>\n");
390 print_indent(fp
, pos
);
391 fprintf(fp
,"</ATTRS>\n");
396 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
400 char buffer
[256], type
[10];
402 LttvAttributeName name
;
404 LttvAttributeValue value
;
406 LttvAttribute
*subtree
;
408 fscanf(fp
,"<ATTRS>");
410 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
412 name
= g_quark_from_string(buffer
);
413 if(strcmp(type
, "ATTRS") == 0) {
415 subtree
= lttv_attribute_find_subdir(self
, name
);
416 lttv_attribute_read_xml(subtree
, fp
);
418 else if(strcmp(type
, "INT") == 0) {
419 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
420 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
423 else if(strcmp(type
, "UINT") == 0) {
424 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
425 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
428 else if(strcmp(type
, "LONG") == 0) {
429 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
430 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
433 else if(strcmp(type
, "ULONG") == 0) {
434 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
435 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
438 else if(strcmp(type
, "FLOAT") == 0) {
440 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
441 res
= fscanf(fp
, " VALUE=%f/>", &d
);
442 *(value
.v_float
) = d
;
445 else if(strcmp(type
, "DOUBLE") == 0) {
446 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
447 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
450 else if(strcmp(type
, "TIME") == 0) {
451 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
452 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
453 &(value
.v_time
->tv_nsec
));
456 else if(strcmp(type
, "POINTER") == 0) {
457 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
458 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
459 g_error("Cannot read a pointer");
461 else if(strcmp(type
, "STRING") == 0) {
462 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
463 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
464 *(value
.v_string
) = g_strdup(buffer
);
467 else if(strcmp(type
, "GOBJECT") == 0) {
468 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
469 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
470 g_error("Cannot read a pointer");
472 else if(strcmp(type
, "NONE") == 0) {
473 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
476 else g_error("Unknown type to read");
478 fscanf(fp
,"</ATTRS>");
481 static LttvAttribute
*
482 new_attribute (LttvAttribute
*self
)
484 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
489 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
491 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
493 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
496 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
497 lttv_attribute_get_number
;
499 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
500 lttv_attribute_named
;
502 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
503 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
505 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
506 LttvAttributeName name
, LttvAttributeValue
*v
))
507 lttv_attribute_get_by_name
;
509 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
510 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
512 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
513 lttv_attribute_remove
;
515 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
516 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
518 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
519 LttvAttributeName name
)) lttv_attribute_find_subdir
;
524 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
526 LttvAttribute
*self
= (LttvAttribute
*)instance
;
527 self
->names
= g_hash_table_new(g_direct_hash
,
529 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
534 attribute_finalize (LttvAttribute
*self
)
537 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
539 for(i
=0;i
<self
->attributes
->len
;i
++) {
540 lttv_attribute_remove(self
, i
);
543 g_hash_table_destroy(self
->names
);
544 g_array_free(self
->attributes
, TRUE
);
549 attribute_class_init (LttvAttributeClass
*klass
)
551 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
553 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
557 lttv_attribute_get_type (void)
559 static GType type
= 0;
561 static const GTypeInfo info
= {
562 sizeof (LttvAttributeClass
),
563 NULL
, /* base_init */
564 NULL
, /* base_finalize */
565 (GClassInitFunc
) attribute_class_init
, /* class_init */
566 NULL
, /* class_finalize */
567 NULL
, /* class_data */
568 sizeof (LttvAttribute
),
570 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
571 NULL
/* value handling */
574 static const GInterfaceInfo iattribute_info
= {
575 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
576 NULL
, /* interface_finalize */
577 NULL
/* interface_data */
580 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
582 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);