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 LttvAttributeValue
address_of_value(LttvAttributeType t
, AttributeValue
*v
)
46 LttvAttributeValue va
;
49 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
50 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
51 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
52 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
53 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
54 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
55 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
56 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
57 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
58 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
59 case LTTV_NONE
: break;
65 AttributeValue
init_value(LttvAttributeType t
)
70 case LTTV_INT
: v
.dv_int
= 0; break;
71 case LTTV_UINT
: v
.dv_uint
= 0; break;
72 case LTTV_LONG
: v
.dv_long
= 0; break;
73 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
74 case LTTV_FLOAT
: v
.dv_float
= 0; break;
75 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
76 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
77 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
78 case LTTV_STRING
: v
.dv_string
= NULL
; break;
79 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
80 case LTTV_NONE
: break;
87 lttv_attribute_get_number(LttvAttribute
*self
)
89 return self
->attributes
->len
;
94 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
102 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
103 LttvAttributeValue
*v
)
107 a
= &g_array_index(self
->attributes
, Attribute
, i
);
109 *v
= address_of_value(a
->type
, &(a
->value
));
115 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
116 LttvAttributeValue
*v
)
124 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
125 if(p
== NULL
) return LTTV_NONE
;
127 i
= GPOINTER_TO_UINT(p
);
129 a
= &g_array_index(self
->attributes
, Attribute
, i
);
130 *v
= address_of_value(a
->type
, &(a
->value
));
136 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
143 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
144 if(i
!= 0) g_error("duplicate entry in attribute table");
148 a
.value
= init_value(t
);
149 g_array_append_val(self
->attributes
, a
);
150 i
= self
->attributes
->len
- 1;
151 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
152 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
153 GUINT_TO_POINTER(i
+ 1));
154 return address_of_value(t
, &(pa
->value
));
158 /* Remove an attribute */
161 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
165 a
= &g_array_index(self
->attributes
, Attribute
, i
);
167 /* If the element is a gobject, unreference it. */
168 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
169 g_object_unref(a
->value
.dv_gobject
);
171 /* Remove the array element and its entry in the name index */
173 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
174 g_array_remove_index_fast(self
->attributes
, i
);
176 /* The element used to replace the removed element has its index entry
177 all wrong now. Reinsert it with its new position. */
179 if(self
->attributes
->len
!= i
){
180 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
181 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
186 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
190 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
191 if(i
== 0) g_error("remove by name non existent attribute");
193 lttv_attribute_remove(self
, i
- 1);
196 /* Create an empty iattribute object and add it as an attribute under the
197 specified name, or return an existing iattribute attribute. If an
198 attribute of that name already exists but is not a GObject supporting the
199 iattribute interface, return NULL. */
201 /*CHECK*/LttvAttribute
*
202 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
210 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
212 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
213 if(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
)) {
214 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
218 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
219 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
220 return (LttvAttribute
*)new;
224 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
225 LttvAttributeType t
, LttvAttributeValue
*v
)
231 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
233 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
234 if(a
->type
!= t
) return FALSE
;
235 *v
= address_of_value(t
, &(a
->value
));
239 *v
= lttv_attribute_add(self
, name
, t
);
244 /*void lttv_attribute_recursive_free(LttvAttribute *self)
250 nb = self->attributes->len;
252 for(i = 0 ; i < nb ; i++) {
253 a = &g_array_index(self->attributes, Attribute, i);
254 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
255 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
258 g_object_unref(self);
262 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
268 LttvAttributeValue value
;
270 nb
= src
->attributes
->len
;
272 for(i
= 0 ; i
< nb
; i
++) {
273 a
= &g_array_index(src
->attributes
, Attribute
, i
);
274 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
275 lttv_attribute_recursive_add(
276 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
277 (LttvAttribute
*)(a
->value
.dv_gobject
));
280 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
283 *value
.v_int
+= a
->value
.dv_int
;
286 *value
.v_uint
+= a
->value
.dv_uint
;
289 *value
.v_long
+= a
->value
.dv_long
;
292 *value
.v_ulong
+= a
->value
.dv_ulong
;
295 *value
.v_float
+= a
->value
.dv_float
;
298 *value
.v_double
+= a
->value
.dv_double
;
301 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
318 print_indent(FILE *fp
, int pos
)
322 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
327 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
333 nb
= self
->attributes
->len
;
335 fprintf(fp
,"<ATTRS>\n");
336 for(i
= 0 ; i
< nb
; i
++) {
337 a
= &g_array_index(self
->attributes
, Attribute
, i
);
338 print_indent(fp
, pos
);
339 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
340 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
341 fprintf(fp
, "TYPE=ATTRS>");
342 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
343 pos
+ indent
, indent
);
348 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
351 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
354 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
357 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
360 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
363 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
366 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
367 a
->value
.dv_time
.tv_nsec
);
370 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
373 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
376 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
379 fprintf(fp
, "TYPE=NONE/>\n");
384 print_indent(fp
, pos
);
385 fprintf(fp
,"</ATTRS>\n");
390 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
394 char buffer
[256], type
[10];
396 LttvAttributeName name
;
398 LttvAttributeValue value
;
400 LttvAttribute
*subtree
;
402 fscanf(fp
,"<ATTRS>");
404 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
406 name
= g_quark_from_string(buffer
);
407 if(strcmp(type
, "ATTRS") == 0) {
409 subtree
= lttv_attribute_find_subdir(self
, name
);
410 lttv_attribute_read_xml(subtree
, fp
);
412 else if(strcmp(type
, "INT") == 0) {
413 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
414 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
417 else if(strcmp(type
, "UINT") == 0) {
418 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
419 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
422 else if(strcmp(type
, "LONG") == 0) {
423 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
424 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
427 else if(strcmp(type
, "ULONG") == 0) {
428 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
429 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
432 else if(strcmp(type
, "FLOAT") == 0) {
434 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
435 res
= fscanf(fp
, " VALUE=%f/>", &d
);
436 *(value
.v_float
) = d
;
439 else if(strcmp(type
, "DOUBLE") == 0) {
440 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
441 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
444 else if(strcmp(type
, "TIME") == 0) {
445 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
446 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
447 &(value
.v_time
->tv_nsec
));
450 else if(strcmp(type
, "POINTER") == 0) {
451 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
452 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
453 g_error("Cannot read a pointer");
455 else if(strcmp(type
, "STRING") == 0) {
456 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
457 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
458 *(value
.v_string
) = g_strdup(buffer
);
461 else if(strcmp(type
, "GOBJECT") == 0) {
462 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
463 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
464 g_error("Cannot read a pointer");
466 else if(strcmp(type
, "NONE") == 0) {
467 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
470 else g_error("Unknown type to read");
472 fscanf(fp
,"</ATTRS>");
475 static LttvAttribute
*
476 new_attribute (LttvAttribute
*self
)
478 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
483 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
485 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
487 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
490 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
491 lttv_attribute_get_number
;
493 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
494 lttv_attribute_named
;
496 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
497 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
499 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
500 LttvAttributeName name
, LttvAttributeValue
*v
))
501 lttv_attribute_get_by_name
;
503 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
504 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
506 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
507 lttv_attribute_remove
;
509 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
510 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
512 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
513 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
, g_direct_equal
);
523 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
528 attribute_finalize (LttvAttribute
*self
)
531 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
533 for(i
=0;i
<self
->attributes
->len
;i
++) {
534 lttv_attribute_remove(self
, i
);
537 g_hash_table_destroy(self
->names
);
538 g_array_free(self
->attributes
, TRUE
);
543 attribute_class_init (LttvAttributeClass
*klass
)
545 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
547 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
551 lttv_attribute_get_type (void)
553 static GType type
= 0;
555 static const GTypeInfo info
= {
556 sizeof (LttvAttributeClass
),
557 NULL
, /* base_init */
558 NULL
, /* base_finalize */
559 (GClassInitFunc
) attribute_class_init
, /* class_init */
560 NULL
, /* class_finalize */
561 NULL
, /* class_data */
562 sizeof (LttvAttribute
),
564 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
565 NULL
/* value handling */
568 static const GInterfaceInfo iattribute_info
= {
569 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
570 NULL
, /* interface_finalize */
571 NULL
/* interface_data */
574 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
576 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);