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 /* Remove the array element and its entry in the name index */
166 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
167 g_array_remove_index_fast(self
->attributes
, i
);
169 /* The element used to replace the removed element has its index entry
170 all wrong now. Reinsert it with its new position. */
172 if(self
->attributes
->len
!= i
){
173 g_hash_table_remove(self
->names
, GUINT_TO_POINTER(a
->name
));
174 g_hash_table_insert(self
->names
, GUINT_TO_POINTER(a
->name
), GUINT_TO_POINTER(i
+ 1));
179 lttv_attribute_remove_by_name(LttvAttribute
*self
, LttvAttributeName name
)
183 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
184 if(i
== 0) g_error("remove by name non existent attribute");
186 lttv_attribute_remove(self
, i
- 1);
189 /* Create an empty iattribute object and add it as an attribute under the
190 specified name, or return an existing iattribute attribute. If an
191 attribute of that name already exists but is not a GObject supporting the
192 iattribute interface, return NULL. */
194 /*CHECK*/LttvAttribute
*
195 lttv_attribute_find_subdir(LttvAttribute
*self
, LttvAttributeName name
)
203 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
205 a
= g_array_index(self
->attributes
, Attribute
, i
- 1);
206 if(a
.type
== LTTV_GOBJECT
&& LTTV_IS_IATTRIBUTE(a
.value
.dv_gobject
)) {
207 return LTTV_ATTRIBUTE(a
.value
.dv_gobject
);
211 new = g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
212 *(lttv_attribute_add(self
, name
, LTTV_GOBJECT
).v_gobject
) = G_OBJECT(new);
213 return (LttvAttribute
*)new;
217 lttv_attribute_find(LttvAttribute
*self
, LttvAttributeName name
,
218 LttvAttributeType t
, LttvAttributeValue
*v
)
224 i
= (unsigned)g_hash_table_lookup(self
->names
, GUINT_TO_POINTER(name
));
226 a
= &g_array_index(self
->attributes
, Attribute
, i
- 1);
227 if(a
->type
!= t
) return FALSE
;
228 *v
= address_of_value(t
, &(a
->value
));
232 *v
= lttv_attribute_add(self
, name
, t
);
237 void lttv_attribute_recursive_free(LttvAttribute
*self
)
243 nb
= self
->attributes
->len
;
245 for(i
= 0 ; i
< nb
; i
++) {
246 a
= &g_array_index(self
->attributes
, Attribute
, i
);
247 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
248 lttv_attribute_recursive_free((LttvAttribute
*)(a
->value
.dv_gobject
));
251 g_object_unref(self
);
255 void lttv_attribute_recursive_add(LttvAttribute
*dest
, LttvAttribute
*src
)
261 LttvAttributeValue value
;
263 nb
= src
->attributes
->len
;
265 for(i
= 0 ; i
< nb
; i
++) {
266 a
= &g_array_index(src
->attributes
, Attribute
, i
);
267 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
268 lttv_attribute_recursive_add(
269 /*CHECK*/(LttvAttribute
*)lttv_attribute_find_subdir(dest
, a
->name
),
270 (LttvAttribute
*)(a
->value
.dv_gobject
));
273 g_assert(lttv_attribute_find(dest
, a
->name
, a
->type
, &value
));
276 *value
.v_int
+= a
->value
.dv_int
;
279 *value
.v_uint
+= a
->value
.dv_uint
;
282 *value
.v_long
+= a
->value
.dv_long
;
285 *value
.v_ulong
+= a
->value
.dv_ulong
;
288 *value
.v_float
+= a
->value
.dv_float
;
291 *value
.v_double
+= a
->value
.dv_double
;
294 *value
.v_time
= ltt_time_add(*value
.v_time
, a
->value
.dv_time
);
311 print_indent(FILE *fp
, int pos
)
315 for(i
= 0 ; i
< pos
; i
++) putc(' ', fp
);
320 lttv_attribute_write_xml(LttvAttribute
*self
, FILE *fp
, int pos
, int indent
)
326 nb
= self
->attributes
->len
;
328 fprintf(fp
,"<ATTRS>\n");
329 for(i
= 0 ; i
< nb
; i
++) {
330 a
= &g_array_index(self
->attributes
, Attribute
, i
);
331 print_indent(fp
, pos
);
332 fprintf(fp
, "<ATTR NAME=\"%s\" ", a
->name
);
333 if(a
->type
== LTTV_GOBJECT
&& LTTV_IS_ATTRIBUTE(a
->value
.dv_gobject
)) {
334 fprintf(fp
, "TYPE=ATTRS>");
335 lttv_attribute_write_xml((LttvAttribute
*)(a
->value
.dv_gobject
), fp
,
336 pos
+ indent
, indent
);
341 fprintf(fp
, "TYPE=INT VALUE=%d/>\n", a
->value
.dv_int
);
344 fprintf(fp
, "TYPE=UINT VALUE=%u/>\n", a
->value
.dv_uint
);
347 fprintf(fp
, "TYPE=LONG VALUE=%ld/>\n", a
->value
.dv_long
);
350 fprintf(fp
, "TYPE=ULONG VALUE=%lu/>\n", a
->value
.dv_ulong
);
353 fprintf(fp
, "TYPE=FLOAT VALUE=%f/>\n", a
->value
.dv_float
);
356 fprintf(fp
, "TYPE=DOUBLE VALUE=%f/>\n", a
->value
.dv_double
);
359 fprintf(fp
, "TYPE=TIME SEC=%u NSEC=%u/>\n", a
->value
.dv_time
.tv_sec
,
360 a
->value
.dv_time
.tv_nsec
);
363 fprintf(fp
, "TYPE=POINTER VALUE=%p/>\n", a
->value
.dv_pointer
);
366 fprintf(fp
, "TYPE=STRING VALUE=\"%s\"/>\n", a
->value
.dv_string
);
369 fprintf(fp
, "TYPE=GOBJECT VALUE=%p/>\n", a
->value
.dv_gobject
);
372 fprintf(fp
, "TYPE=NONE/>\n");
377 print_indent(fp
, pos
);
378 fprintf(fp
,"</ATTRS>\n");
383 lttv_attribute_read_xml(LttvAttribute
*self
, FILE *fp
)
389 char buffer
[256], type
[10];
391 LttvAttributeName name
;
393 LttvAttributeValue value
;
395 LttvAttribute
*subtree
;
397 fscanf(fp
,"<ATTRS>");
399 res
= fscanf(fp
, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer
, type
);
401 name
= g_quark_from_string(buffer
);
402 if(strcmp(type
, "ATTRS") == 0) {
404 subtree
= lttv_attribute_find_subdir(self
, name
);
405 lttv_attribute_read_xml(subtree
, fp
);
407 else if(strcmp(type
, "INT") == 0) {
408 value
= lttv_attribute_add(self
, name
, LTTV_INT
);
409 res
= fscanf(fp
, " VALUE=%d/>", value
.v_int
);
412 else if(strcmp(type
, "UINT") == 0) {
413 value
= lttv_attribute_add(self
, name
, LTTV_UINT
);
414 res
= fscanf(fp
, " VALUE=%u/>", value
.v_uint
);
417 else if(strcmp(type
, "LONG") == 0) {
418 value
= lttv_attribute_add(self
, name
, LTTV_LONG
);
419 res
= fscanf(fp
, " VALUE=%ld/>", value
.v_long
);
422 else if(strcmp(type
, "ULONG") == 0) {
423 value
= lttv_attribute_add(self
, name
, LTTV_ULONG
);
424 res
= fscanf(fp
, " VALUE=%lu/>", value
.v_ulong
);
427 else if(strcmp(type
, "FLOAT") == 0) {
429 value
= lttv_attribute_add(self
, name
, LTTV_FLOAT
);
430 res
= fscanf(fp
, " VALUE=%f/>", &d
);
431 *(value
.v_float
) = d
;
434 else if(strcmp(type
, "DOUBLE") == 0) {
435 value
= lttv_attribute_add(self
, name
, LTTV_DOUBLE
);
436 res
= fscanf(fp
, " VALUE=%f/>", value
.v_double
);
439 else if(strcmp(type
, "TIME") == 0) {
440 value
= lttv_attribute_add(self
, name
, LTTV_TIME
);
441 res
= fscanf(fp
, " SEC=%u NSEC=%u/>", &(value
.v_time
->tv_sec
),
442 &(value
.v_time
->tv_nsec
));
445 else if(strcmp(type
, "POINTER") == 0) {
446 value
= lttv_attribute_add(self
, name
, LTTV_POINTER
);
447 res
= fscanf(fp
, " VALUE=%p/>", value
.v_pointer
);
448 g_error("Cannot read a pointer");
450 else if(strcmp(type
, "STRING") == 0) {
451 value
= lttv_attribute_add(self
, name
, LTTV_STRING
);
452 res
= fscanf(fp
, " VALUE=\"%256[^\"]\"/>", buffer
);
453 *(value
.v_string
) = g_strdup(buffer
);
456 else if(strcmp(type
, "GOBJECT") == 0) {
457 value
= lttv_attribute_add(self
, name
, LTTV_GOBJECT
);
458 res
= fscanf(fp
, " VALUE=%p/>", value
.v_gobject
);
459 g_error("Cannot read a pointer");
461 else if(strcmp(type
, "NONE") == 0) {
462 value
= lttv_attribute_add(self
, name
, LTTV_NONE
);
465 else g_error("Unknown type to read");
467 fscanf(fp
,"</ATTRS>");
472 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
474 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
476 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
477 lttv_attribute_get_number
;
479 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
480 lttv_attribute_named
;
482 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
483 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
485 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
486 LttvAttributeName name
, LttvAttributeValue
*v
))
487 lttv_attribute_get_by_name
;
489 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
490 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
492 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
493 lttv_attribute_remove
;
495 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
496 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
498 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
499 LttvAttributeName name
)) lttv_attribute_find_subdir
;
504 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
506 LttvAttribute
*self
= (LttvAttribute
*)instance
;
507 self
->names
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
508 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
513 attribute_finalize (LttvAttribute
*self
)
515 g_hash_table_destroy(self
->names
);
516 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
517 g_array_free(self
->attributes
, TRUE
);
518 G_OBJECT_CLASS(g_type_class_peek_parent(
519 g_type_class_peek(LTTV_ATTRIBUTE_TYPE
)))->finalize(G_OBJECT(self
));
524 attribute_class_init (LttvAttributeClass
*klass
)
526 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
528 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
532 lttv_attribute_get_type (void)
534 static GType type
= 0;
536 static const GTypeInfo info
= {
537 sizeof (LttvAttributeClass
),
538 NULL
, /* base_init */
539 NULL
, /* base_finalize */
540 (GClassInitFunc
) attribute_class_init
, /* class_init */
541 NULL
, /* class_finalize */
542 NULL
, /* class_data */
543 sizeof (LttvAttribute
),
545 (GInstanceInitFunc
) attribute_instance_init
/* instance_init */
548 static const GInterfaceInfo iattribute_info
= {
549 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
550 NULL
, /* interface_finalize */
551 NULL
/* interface_data */
554 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
556 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);