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\" ", g_quark_to_string(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>");
470 static LttvAttribute
*
471 new_attribute (LttvAttribute
*self
)
473 return g_object_new(LTTV_ATTRIBUTE_TYPE
, NULL
);
478 attribute_interface_init (gpointer g_iface
, gpointer iface_data
)
480 LttvIAttributeClass
*klass
= (LttvIAttributeClass
*)g_iface
;
482 klass
->new_attribute
= (LttvIAttribute
* (*) (LttvIAttribute
*self
))
485 klass
->get_number
= (unsigned int (*) (LttvIAttribute
*self
))
486 lttv_attribute_get_number
;
488 klass
->named
= (gboolean (*) (LttvIAttribute
*self
, gboolean
*homogeneous
))
489 lttv_attribute_named
;
491 klass
->get
= (LttvAttributeType (*) (LttvIAttribute
*self
, unsigned i
,
492 LttvAttributeName
*name
, LttvAttributeValue
*v
)) lttv_attribute_get
;
494 klass
->get_by_name
= (LttvAttributeType (*) (LttvIAttribute
*self
,
495 LttvAttributeName name
, LttvAttributeValue
*v
))
496 lttv_attribute_get_by_name
;
498 klass
->add
= (LttvAttributeValue (*) (LttvIAttribute
*self
,
499 LttvAttributeName name
, LttvAttributeType t
)) lttv_attribute_add
;
501 klass
->remove
= (void (*) (LttvIAttribute
*self
, unsigned i
))
502 lttv_attribute_remove
;
504 klass
->remove_by_name
= (void (*) (LttvIAttribute
*self
,
505 LttvAttributeName name
)) lttv_attribute_remove_by_name
;
507 klass
->find_subdir
= (LttvIAttribute
* (*) (LttvIAttribute
*self
,
508 LttvAttributeName name
)) lttv_attribute_find_subdir
;
514 attribute_instance_init (GTypeInstance
*instance
, gpointer g_class
)
516 LttvAttribute
*self
= (LttvAttribute
*)instance
;
517 self
->names
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
518 self
->attributes
= g_array_new(FALSE
, FALSE
, sizeof(Attribute
));
523 attribute_finalize (LttvAttribute
*self
)
525 g_hash_table_destroy(self
->names
);
526 g_log(G_LOG_DOMAIN
, G_LOG_LEVEL_DEBUG
, "attribute_finalize()");
527 g_array_free(self
->attributes
, TRUE
);
528 G_OBJECT_CLASS(g_type_class_peek_parent(
529 g_type_class_peek(LTTV_ATTRIBUTE_TYPE
)))->finalize(G_OBJECT(self
));
534 attribute_class_init (LttvAttributeClass
*klass
)
536 GObjectClass
*gobject_class
= G_OBJECT_CLASS(klass
);
538 gobject_class
->finalize
= (void (*)(GObject
*self
))attribute_finalize
;
542 lttv_attribute_get_type (void)
544 static GType type
= 0;
546 static const GTypeInfo info
= {
547 sizeof (LttvAttributeClass
),
548 NULL
, /* base_init */
549 NULL
, /* base_finalize */
550 (GClassInitFunc
) attribute_class_init
, /* class_init */
551 NULL
, /* class_finalize */
552 NULL
, /* class_data */
553 sizeof (LttvAttribute
),
555 (GInstanceInitFunc
) attribute_instance_init
/* instance_init */
558 static const GInterfaceInfo iattribute_info
= {
559 (GInterfaceInitFunc
) attribute_interface_init
, /* interface_init */
560 NULL
, /* interface_finalize */
561 NULL
/* interface_data */
564 type
= g_type_register_static (G_TYPE_OBJECT
, "LttvAttributeType", &info
,
566 g_type_add_interface_static (type
, LTTV_IATTRIBUTE_TYPE
, &iattribute_info
);