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>
22 #include <ltt/compiler.h>
24 typedef union _AttributeValue
{
28 unsigned long dv_ulong
;
38 typedef struct _Attribute
{
39 LttvAttributeName name
;
40 LttvAttributeType type
;
45 static __inline__ LttvAttributeValue
address_of_value(LttvAttributeType t
,
48 LttvAttributeValue va
;
51 case LTTV_INT
: va
.v_int
= &v
->dv_int
; break;
52 case LTTV_UINT
: va
.v_uint
= &v
->dv_uint
; break;
53 case LTTV_LONG
: va
.v_long
= &v
->dv_long
; break;
54 case LTTV_ULONG
: va
.v_ulong
= &v
->dv_ulong
; break;
55 case LTTV_FLOAT
: va
.v_float
= &v
->dv_float
; break;
56 case LTTV_DOUBLE
: va
.v_double
= &v
->dv_double
; break;
57 case LTTV_TIME
: va
.v_time
= &v
->dv_time
; break;
58 case LTTV_POINTER
: va
.v_pointer
= &v
->dv_pointer
; break;
59 case LTTV_STRING
: va
.v_string
= &v
->dv_string
; break;
60 case LTTV_GOBJECT
: va
.v_gobject
= &v
->dv_gobject
; break;
61 case LTTV_NONE
: break;
67 AttributeValue
init_value(LttvAttributeType t
)
72 case LTTV_INT
: v
.dv_int
= 0; break;
73 case LTTV_UINT
: v
.dv_uint
= 0; break;
74 case LTTV_LONG
: v
.dv_long
= 0; break;
75 case LTTV_ULONG
: v
.dv_ulong
= 0; break;
76 case LTTV_FLOAT
: v
.dv_float
= 0; break;
77 case LTTV_DOUBLE
: v
.dv_double
= 0; break;
78 case LTTV_TIME
: v
.dv_time
.tv_sec
= 0; v
.dv_time
.tv_nsec
= 0; break;
79 case LTTV_POINTER
: v
.dv_pointer
= NULL
; break;
80 case LTTV_STRING
: v
.dv_string
= NULL
; break;
81 case LTTV_GOBJECT
: v
.dv_gobject
= NULL
; break;
82 case LTTV_NONE
: break;
89 lttv_attribute_get_number(LttvAttribute
*self
)
91 return self
->attributes
->len
;
96 lttv_attribute_named(LttvAttribute
*self
, gboolean
*homogeneous
)
104 lttv_attribute_get(LttvAttribute
*self
, unsigned i
, LttvAttributeName
*name
,
105 LttvAttributeValue
*v
)
109 a
= &g_array_index(self
->attributes
, Attribute
, i
);
111 *v
= address_of_value(a
->type
, &(a
->value
));
117 lttv_attribute_get_by_name(LttvAttribute
*self
, LttvAttributeName name
,
118 LttvAttributeValue
*v
)
126 p
= g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
127 if(p
== NULL
) return LTTV_NONE
;
129 i
= GPOINTER_TO_UINT(p
);
131 a
= &g_array_index(self
->attributes
, Attribute
, i
);
132 *v
= address_of_value(a
->type
, &(a
->value
));
138 lttv_attribute_add(LttvAttribute
*self
, LttvAttributeName name
,
145 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
146 if(i
!= 0) g_error("duplicate entry in attribute table");
150 a
.value
= init_value(t
);
151 g_array_append_val(self
->attributes
, a
);
152 i
= self
->attributes
->len
- 1;
153 pa
= &g_array_index(self
->attributes
, Attribute
, i
);
154 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(name
),
155 GUINT_TO_POINTER(i
+ 1));
156 return address_of_value(t
, &(pa
->value
));
160 /* Remove an attribute */
163 lttv_attribute_remove(LttvAttribute
*self
, unsigned i
)
167 a
= &g_array_index(self
->attributes
, Attribute
, i
);
169 /* If the element is a gobject, unreference it. */
170 if(a
->type
== LTTV_GOBJECT
&& a
->value
.dv_gobject
!= NULL
)
171 g_object_unref(a
->value
.dv_gobject
);
173 /* Remove the array element and its entry in the name index */
175 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
176 g_array_remove_index_fast(self
->attributes
, i
);
178 /* The element used to replace the removed element has its index entry
179 all wrong now. Reinsert it with its new position. */
181 if(likely(self
->attributes
->len
!= i
)){
182 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
183 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
188 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
192 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
193 if(unlikely(i
== 0)) g_error("remove by name non existent attribute");
195 lttv_attribute_remove(self
, i
- 1);
198 /* Create an empty iattribute object and add it as an attribute under the
199 specified name, or return an existing iattribute attribute. If an
200 attribute of that name already exists but is not a GObject supporting the
201 iattribute interface, return NULL. */
203 /*CHECK*/LttvAttribute
*
204 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
212 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
214 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
215 if(likely(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
))) {
216 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
220 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
221 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
222 return (LttvAttribute
*)new;
226 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
227 LttvAttributeType t
, LttvAttributeValue
*v
)
233 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
235 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
236 if(unlikely(a
->type
!= t
)) return FALSE
;
237 *v
= address_of_value(t
, &(a
->value
));
241 *v
= lttv_attribute_add(self
, name
, t
);
246 /*void lttv_attribute_recursive_free(LttvAttribute *self)
252 nb = self->attributes->len;
254 for(i = 0 ; i < nb ; i++) {
255 a = &g_array_index(self->attributes, Attribute, i);
256 if(a->type == LTTV_GOBJECT && LTTV_IS_ATTRIBUTE(a->value.dv_gobject)) {
257 lttv_attribute_recursive_free((LttvAttribute *)(a->value.dv_gobject));
260 g_object_unref(self);
264 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
270 LttvAttributeValue value
;
272 nb
= src
->attributes
->len
;
274 for(i
= 0 ; i
< nb
; i
++) {
275 a
= &g_array_index(src
->attributes
, Attribute
, i
);
276 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
277 lttv_attribute_recursive_add(
278 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
279 (LttvAttribute
*)(a
->value
.dv_gobject
));
282 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
285 *value
.v_int
+= a
->value
.dv_int
;
288 *value
.v_uint
+= a
->value
.dv_uint
;
291 *value
.v_long
+= a
->value
.dv_long
;
294 *value
.v_ulong
+= a
->value
.dv_ulong
;
297 *value
.v_float
+= a
->value
.dv_float
;
300 *value
.v_double
+= a
->value
.dv_double
;
303 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
320 print_indent(FILE *fp
, int pos
)
324 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
329 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
335 nb
= self
->attributes
->len
;
337 fprintf(fp
,"<ATTRS>\n");
338 for(i
= 0 ; i
< nb
; i
++) {
339 a
= &g_array_index(self
->attributes
, Attribute
, i
);
340 print_indent(fp
, pos
);
341 fprintf(fp
, "<ATTR NAME=\"%s\" ", g_quark_to_string(a
->name
));
342 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
343 fprintf(fp
, "TYPE=ATTRS>");
344 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
345 pos
+ indent
, indent
);
350 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
353 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
356 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
359 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
362 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
365 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
368 fprintf(fp
, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a
->value
.dv_time
.tv_sec
,
369 a
->value
.dv_time
.tv_nsec
);
372 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
375 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
378 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
381 fprintf(fp
, "TYPE=NONE/>\n");
386 print_indent(fp
, pos
);
387 fprintf(fp
,"</ATTRS>\n");
392 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
396 char buffer
[256], type
[10];
398 LttvAttributeName name
;
400 LttvAttributeValue value
;
402 LttvAttribute
*subtree
;
404 fscanf(fp
,"<ATTRS>");
406 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
408 name
= g_quark_from_string(buffer
);
409 if(strcmp(type
, "ATTRS") == 0) {
411 subtree
= lttv_attribute_find_subdir(self
, name
);
412 lttv_attribute_read_xml(subtree
, fp
);
414 else if(strcmp(type
, "INT") == 0) {
415 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
416 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
419 else if(strcmp(type
, "UINT") == 0) {
420 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
421 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
424 else if(strcmp(type
, "LONG") == 0) {
425 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
426 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
429 else if(strcmp(type
, "ULONG") == 0) {
430 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
431 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
434 else if(strcmp(type
, "FLOAT") == 0) {
436 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
437 res
= fscanf(fp
, " VALUE=%f/>", &d
);
438 *(value
.v_float
) = d
;
441 else if(strcmp(type
, "DOUBLE") == 0) {
442 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
443 res
= fscanf(fp
, " VALUE=%lf/>", value
.v_double
);
446 else if(strcmp(type
, "TIME") == 0) {
447 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
448 res
= fscanf(fp
, " SEC=%lu NSEC=%lu/>", &(value
.v_time
->tv_sec
),
449 &(value
.v_time
->tv_nsec
));
452 else if(strcmp(type
, "POINTER") == 0) {
453 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
454 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
455 g_error("Cannot read a pointer");
457 else if(strcmp(type
, "STRING") == 0) {
458 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
459 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
460 *(value
.v_string
) = g_strdup(buffer
);
463 else if(strcmp(type
, "GOBJECT") == 0) {
464 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
465 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
466 g_error("Cannot read a pointer");
468 else if(strcmp(type
, "NONE") == 0) {
469 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
472 else g_error("Unknown type to read");
474 fscanf(fp
,"</ATTRS>");
477 static LttvAttribute
*
478 new_attribute (LttvAttribute
*self
)
480 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
485 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
487 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
489 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
492 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
493 lttv_attribute_get_number
;
495 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
496 lttv_attribute_named
;
498 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
499 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
501 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
502 LttvAttributeName name
, LttvAttributeValue
*v
))
503 lttv_attribute_get_by_name
;
505 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
506 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
508 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
509 lttv_attribute_remove
;
511 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
512 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
514 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
515 LttvAttributeName name
)) lttv_attribute_find_subdir
;
520 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
522 LttvAttribute
*self
= (LttvAttribute
*)instance
;
523 self
->names
= g_hash_table_new(g_direct_hash
,
525 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
530 attribute_finalize (LttvAttribute
*self
)
533 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
535 for(i
=0;i
<self
->attributes
->len
;i
++) {
536 lttv_attribute_remove(self
, i
);
539 g_hash_table_destroy(self
->names
);
540 g_array_free(self
->attributes
, TRUE
);
545 attribute_class_init (LttvAttributeClass
*klass
)
547 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
549 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
553 lttv_attribute_get_type (void)
555 static GType type
= 0;
557 static const GTypeInfo info
= {
558 sizeof (LttvAttributeClass
),
559 NULL
, /* base_init */
560 NULL
, /* base_finalize */
561 (GClassInitFunc
) attribute_class_init
, /* class_init */
562 NULL
, /* class_finalize */
563 NULL
, /* class_data */
564 sizeof (LttvAttribute
),
566 (GInstanceInitFunc
) attribute_instance_init
, /* instance_init */
567 NULL
/* value handling */
570 static const GInterfaceInfo iattribute_info
= {
571 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
572 NULL
, /* interface_finalize */
573 NULL
/* interface_data */
576 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
578 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);