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,
19 #include <lttv/attribute.h>
22 typedef union _AttributeValue
{
26 unsigned long dv_ulong
;
36 typedef struct _Attribute
{
37 LttvAttributeName name
;
38 LttvAttributeType type
;
43 LttvAttributeValue
address_of_value(LttvAttributeType t
, AttributeValue
*v
)
45 LttvAttributeValue va
;
48 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
49 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
50 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
51 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
52 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
53 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
54 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
55 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
56 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
57 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
63 AttributeValue
init_value(LttvAttributeType t
)
68 case LTTV_INT
: v
.dv_int
= 0; break;
69 case LTTV_UINT
: v
.dv_uint
= 0; break;
70 case LTTV_LONG
: v
.dv_long
= 0; break;
71 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
72 case LTTV_FLOAT
: v
.dv_float
= 0; break;
73 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
74 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
75 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
76 case LTTV_STRING
: v
.dv_string
= NULL
; break;
77 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
84 lttv_attribute_get_number(LttvAttribute
*self
)
86 return self
->attributes
->len
;
91 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
99 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
100 LttvAttributeValue
*v
)
104 a
= &g_array_index(self
->attributes
, Attribute
, i
);
106 *v
= address_of_value(a
->type
, &(a
->value
));
112 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
113 LttvAttributeValue
*v
)
121 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
122 if(p
== NULL
) return LTTV_NONE
;
124 i
= GPOINTER_TO_UINT(p
);
126 a
= &g_array_index(self
->attributes
, Attribute
, i
);
127 *v
= address_of_value(a
->type
, &(a
->value
));
133 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
140 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
141 if(i
!= 0) g_error("duplicate entry in attribute table");
145 a
.value
= init_value(t
);
146 g_array_append_val(self
->attributes
, a
);
147 i
= self
->attributes
->len
- 1;
148 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
149 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
150 GUINT_TO_POINTER(i
+ 1));
151 return address_of_value(t
, &(pa
->value
));
155 /* Remove an attribute */
158 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
162 a
= &g_array_index(self
->attributes
, Attribute
, i
);
164 /* If the element is a gobject, unreference it. */
165 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
166 g_object_unref(a
->value
.dv_gobject
);
168 /* Remove the array element and its entry in the name index */
170 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
171 g_array_remove_index_fast(self
->attributes
, i
);
173 /* The element used to replace the removed element has its index entry
174 all wrong now. Reinsert it with its new position. */
176 if(self
->attributes
->len
!= i
){
177 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
178 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
183 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
187 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
188 if(i
== 0) g_error("remove by name non existent attribute");
190 lttv_attribute_remove(self
, i
- 1);
193 /* Create an empty iattribute object and add it as an attribute under the
194 specified name, or return an existing iattribute attribute. If an
195 attribute of that name already exists but is not a GObject supporting the
196 iattribute interface, return NULL. */
198 /*CHECK*/LttvAttribute
*
199 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
207 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
209 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
210 if(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
)) {
211 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
215 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
216 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
217 return (LttvAttribute
*)new;
221 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
222 LttvAttributeType t
, LttvAttributeValue
*v
)
228 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
230 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
231 if(a
->type
!= t
) return FALSE
;
232 *v
= address_of_value(t
, &(a
->value
));
236 *v
= lttv_attribute_add(self
, name
, t
);
241 /*void lttv_attribute_recursive_free(LttvAttribute *self)
247 nb = self->attributes->len;
249 for(i = 0 ; i < nb ; i++) {
250 a = &g_array_index(self->attributes, Attribute, i);
251 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
252 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
255 g_object_unref(self);
259 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
265 LttvAttributeValue value
;
267 nb
= src
->attributes
->len
;
269 for(i
= 0 ; i
< nb
; i
++) {
270 a
= &g_array_index(src
->attributes
, Attribute
, i
);
271 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
272 lttv_attribute_recursive_add(
273 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
274 (LttvAttribute
*)(a
->value
.dv_gobject
));
277 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
280 *value
.v_int
+= a
->value
.dv_int
;
283 *value
.v_uint
+= a
->value
.dv_uint
;
286 *value
.v_long
+= a
->value
.dv_long
;
289 *value
.v_ulong
+= a
->value
.dv_ulong
;
292 *value
.v_float
+= a
->value
.dv_float
;
295 *value
.v_double
+= a
->value
.dv_double
;
298 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
315 print_indent(FILE *fp
, int pos
)
319 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
324 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
330 nb
= self
->attributes
->len
;
332 fprintf(fp
,"<ATTRS>\n");
333 for(i
= 0 ; i
< nb
; i
++) {
334 a
= &g_array_index(self
->attributes
, Attribute
, i
);
335 print_indent(fp
, pos
);
336 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
337 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
338 fprintf(fp
, "TYPE=ATTRS>");
339 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
340 pos
+ indent
, indent
);
345 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
348 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
351 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
354 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
357 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
360 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
363 fprintf(fp
, "TYPE=TIME SEC=%u NSEC=%u/>\n", a
->value
.dv_time
.tv_sec
,
364 a
->value
.dv_time
.tv_nsec
);
367 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
370 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
373 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
376 fprintf(fp
, "TYPE=NONE/>\n");
381 print_indent(fp
, pos
);
382 fprintf(fp
,"</ATTRS>\n");
387 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
393 char buffer
[256], type
[10];
395 LttvAttributeName name
;
397 LttvAttributeValue value
;
399 LttvAttribute
*subtree
;
401 fscanf(fp
,"<ATTRS>");
403 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
405 name
= g_quark_from_string(buffer
);
406 if(strcmp(type
, "ATTRS") == 0) {
408 subtree
= lttv_attribute_find_subdir(self
, name
);
409 lttv_attribute_read_xml(subtree
, fp
);
411 else if(strcmp(type
, "INT") == 0) {
412 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
413 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
416 else if(strcmp(type
, "UINT") == 0) {
417 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
418 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
421 else if(strcmp(type
, "LONG") == 0) {
422 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
423 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
426 else if(strcmp(type
, "ULONG") == 0) {
427 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
428 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
431 else if(strcmp(type
, "FLOAT") == 0) {
433 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
434 res
= fscanf(fp
, " VALUE=%f/>", &d
);
435 *(value
.v_float
) = d
;
438 else if(strcmp(type
, "DOUBLE") == 0) {
439 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
440 res
= fscanf(fp
, " VALUE=%f/>", value
.v_double
);
443 else if(strcmp(type
, "TIME") == 0) {
444 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
445 res
= fscanf(fp
, " SEC=%u NSEC=%u/>", &(value
.v_time
->tv_sec
),
446 &(value
.v_time
->tv_nsec
));
449 else if(strcmp(type
, "POINTER") == 0) {
450 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
451 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
452 g_error("Cannot read a pointer");
454 else if(strcmp(type
, "STRING") == 0) {
455 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
456 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
457 *(value
.v_string
) = g_strdup(buffer
);
460 else if(strcmp(type
, "GOBJECT") == 0) {
461 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
462 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
463 g_error("Cannot read a pointer");
465 else if(strcmp(type
, "NONE") == 0) {
466 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
469 else g_error("Unknown type to read");
471 fscanf(fp
,"</ATTRS>");
474 static LttvAttribute
*
475 new_attribute (LttvAttribute
*self
)
477 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
482 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
484 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
486 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
489 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
490 lttv_attribute_get_number
;
492 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
493 lttv_attribute_named
;
495 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
496 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
498 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
499 LttvAttributeName name
, LttvAttributeValue
*v
))
500 lttv_attribute_get_by_name
;
502 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
503 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
505 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
506 lttv_attribute_remove
;
508 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
509 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
511 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
512 LttvAttributeName name
)) lttv_attribute_find_subdir
;
518 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
520 LttvAttribute
*self
= (LttvAttribute
*)instance
;
521 self
->names
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
522 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
527 attribute_finalize (LttvAttribute
*self
)
530 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
532 for(i
=0;i
<self
->attributes
->len
;i
++) {
533 lttv_attribute_remove(self
, i
);
536 g_hash_table_destroy(self
->names
);
537 g_array_free(self
->attributes
, TRUE
);
542 attribute_class_init (LttvAttributeClass
*klass
)
544 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
546 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
550 lttv_attribute_get_type (void)
552 static GType type
= 0;
554 static const GTypeInfo info
= {
555 sizeof (LttvAttributeClass
),
556 NULL
, /* base_init */
557 NULL
, /* base_finalize */
558 (GClassInitFunc
) attribute_class_init
, /* class_init */
559 NULL
, /* class_finalize */
560 NULL
, /* class_data */
561 sizeof (LttvAttribute
),
563 (GInstanceInitFunc
) attribute_instance_init
/* instance_init */
566 static const GInterfaceInfo iattribute_info
= {
567 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
568 NULL
, /* interface_finalize */
569 NULL
/* interface_data */
572 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
574 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);