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,
20 #include <lttv/attribute.h>
23 typedef union _AttributeValue
{
27 unsigned long dv_ulong
;
37 typedef struct _Attribute
{
38 LttvAttributeName name
;
39 LttvAttributeType type
;
44 static __inline__ LttvAttributeValue
address_of_value(LttvAttributeType t
,
47 LttvAttributeValue va
;
50 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
51 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
52 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
53 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
54 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
55 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
56 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
57 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
58 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
59 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
60 case LTTV_NONE
: break;
66 AttributeValue
init_value(LttvAttributeType t
)
71 case LTTV_INT
: v
.dv_int
= 0; break;
72 case LTTV_UINT
: v
.dv_uint
= 0; break;
73 case LTTV_LONG
: v
.dv_long
= 0; break;
74 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
75 case LTTV_FLOAT
: v
.dv_float
= 0; break;
76 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
77 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
78 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
79 case LTTV_STRING
: v
.dv_string
= NULL
; break;
80 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
81 case LTTV_NONE
: break;
88 lttv_attribute_get_number(LttvAttribute
*self
)
90 return self
->attributes
->len
;
95 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
103 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
104 LttvAttributeValue
*v
)
108 a
= &g_array_index(self
->attributes
, Attribute
, i
);
110 *v
= address_of_value(a
->type
, &(a
->value
));
116 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
117 LttvAttributeValue
*v
)
125 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
126 if(p
== NULL
) return LTTV_NONE
;
128 i
= GPOINTER_TO_UINT(p
);
130 a
= &g_array_index(self
->attributes
, Attribute
, i
);
131 *v
= address_of_value(a
->type
, &(a
->value
));
137 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
144 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
145 if(i
!= 0) g_error("duplicate entry in attribute table");
149 a
.value
= init_value(t
);
150 g_array_append_val(self
->attributes
, a
);
151 i
= self
->attributes
->len
- 1;
152 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
153 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
154 GUINT_TO_POINTER(i
+ 1));
155 return address_of_value(t
, &(pa
->value
));
159 /* Remove an attribute */
162 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
166 a
= &g_array_index(self
->attributes
, Attribute
, i
);
168 /* If the element is a gobject, unreference it. */
169 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
170 g_object_unref(a
->value
.dv_gobject
);
172 /* Remove the array element and its entry in the name index */
174 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
175 g_array_remove_index_fast(self
->attributes
, i
);
177 /* The element used to replace the removed element has its index entry
178 all wrong now. Reinsert it with its new position. */
180 if(self
->attributes
->len
!= i
){
181 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
182 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
187 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
191 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
192 if(i
== 0) g_error("remove by name non existent attribute");
194 lttv_attribute_remove(self
, i
- 1);
197 /* Create an empty iattribute object and add it as an attribute under the
198 specified name, or return an existing iattribute attribute. If an
199 attribute of that name already exists but is not a GObject supporting the
200 iattribute interface, return NULL. */
202 /*CHECK*/LttvAttribute
*
203 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
211 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
213 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
214 if(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
)) {
215 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
219 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
220 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
221 return (LttvAttribute
*)new;
225 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
226 LttvAttributeType t
, LttvAttributeValue
*v
)
232 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
234 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
235 if(a
->type
!= t
) return FALSE
;
236 *v
= address_of_value(t
, &(a
->value
));
240 *v
= lttv_attribute_add(self
, name
, t
);
245 /*void lttv_attribute_recursive_free(LttvAttribute *self)
251 nb = self->attributes->len;
253 for(i = 0 ; i < nb ; i++) {
254 a = &g_array_index(self->attributes, Attribute, i);
255 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
256 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
259 g_object_unref(self);
263 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
269 LttvAttributeValue value
;
271 nb
= src
->attributes
->len
;
273 for(i
= 0 ; i
< nb
; i
++) {
274 a
= &g_array_index(src
->attributes
, Attribute
, i
);
275 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
276 lttv_attribute_recursive_add(
277 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
278 (LttvAttribute
*)(a
->value
.dv_gobject
));
281 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
284 *value
.v_int
+= a
->value
.dv_int
;
287 *value
.v_uint
+= a
->value
.dv_uint
;
290 *value
.v_long
+= a
->value
.dv_long
;
293 *value
.v_ulong
+= a
->value
.dv_ulong
;
296 *value
.v_float
+= a
->value
.dv_float
;
299 *value
.v_double
+= a
->value
.dv_double
;
302 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
319 print_indent(FILE *fp
, int pos
)
323 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
328 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
334 nb
= self
->attributes
->len
;
336 fprintf(fp
,"<ATTRS>\n");
337 for(i
= 0 ; i
< nb
; i
++) {
338 a
= &g_array_index(self
->attributes
, Attribute
, i
);
339 print_indent(fp
, pos
);
340 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
341 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
342 fprintf(fp
, "TYPE=ATTRS>");
343 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
344 pos
+ indent
, indent
);
349 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
352 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
355 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
358 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
361 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
364 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
367 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
368 a
->value
.dv_time
.tv_nsec
);
371 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
374 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
377 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
380 fprintf(fp
, "TYPE=NONE/>\n");
385 print_indent(fp
, pos
);
386 fprintf(fp
,"</ATTRS>\n");
391 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
395 char buffer
[256], type
[10];
397 LttvAttributeName name
;
399 LttvAttributeValue value
;
401 LttvAttribute
*subtree
;
403 fscanf(fp
,"<ATTRS>");
405 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
407 name
= g_quark_from_string(buffer
);
408 if(strcmp(type
, "ATTRS") == 0) {
410 subtree
= lttv_attribute_find_subdir(self
, name
);
411 lttv_attribute_read_xml(subtree
, fp
);
413 else if(strcmp(type
, "INT") == 0) {
414 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
415 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
418 else if(strcmp(type
, "UINT") == 0) {
419 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
420 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
423 else if(strcmp(type
, "LONG") == 0) {
424 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
425 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
428 else if(strcmp(type
, "ULONG") == 0) {
429 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
430 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
433 else if(strcmp(type
, "FLOAT") == 0) {
435 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
436 res
= fscanf(fp
, " VALUE=%f/>", &d
);
437 *(value
.v_float
) = d
;
440 else if(strcmp(type
, "DOUBLE") == 0) {
441 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
442 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
445 else if(strcmp(type
, "TIME") == 0) {
446 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
447 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
448 &(value
.v_time
->tv_nsec
));
451 else if(strcmp(type
, "POINTER") == 0) {
452 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
453 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
454 g_error("Cannot read a pointer");
456 else if(strcmp(type
, "STRING") == 0) {
457 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
458 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
459 *(value
.v_string
) = g_strdup(buffer
);
462 else if(strcmp(type
, "GOBJECT") == 0) {
463 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
464 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
465 g_error("Cannot read a pointer");
467 else if(strcmp(type
, "NONE") == 0) {
468 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
471 else g_error("Unknown type to read");
473 fscanf(fp
,"</ATTRS>");
476 static LttvAttribute
*
477 new_attribute (LttvAttribute
*self
)
479 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
484 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
486 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
488 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
491 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
492 lttv_attribute_get_number
;
494 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
495 lttv_attribute_named
;
497 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
498 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
500 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
501 LttvAttributeName name
, LttvAttributeValue
*v
))
502 lttv_attribute_get_by_name
;
504 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
505 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
507 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
508 lttv_attribute_remove
;
510 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
511 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
513 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
514 LttvAttributeName name
)) lttv_attribute_find_subdir
;
519 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
521 LttvAttribute
*self
= (LttvAttribute
*)instance
;
522 self
->names
= g_hash_table_new(g_direct_hash
,
524 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
529 attribute_finalize (LttvAttribute
*self
)
532 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
534 for(i
=0;i
<self
->attributes
->len
;i
++) {
535 lttv_attribute_remove(self
, i
);
538 g_hash_table_destroy(self
->names
);
539 g_array_free(self
->attributes
, TRUE
);
544 attribute_class_init (LttvAttributeClass
*klass
)
546 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
548 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
552 lttv_attribute_get_type (void)
554 static GType type
= 0;
556 static const GTypeInfo info
= {
557 sizeof (LttvAttributeClass
),
558 NULL
, /* base_init */
559 NULL
, /* base_finalize */
560 (GClassInitFunc
) attribute_class_init
, /* class_init */
561 NULL
, /* class_finalize */
562 NULL
, /* class_data */
563 sizeof (LttvAttribute
),
565 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
566 NULL
/* value handling */
569 static const GInterfaceInfo iattribute_info
= {
570 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
571 NULL
, /* interface_finalize */
572 NULL
/* interface_data */
575 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
577 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);