header missing
[lttv.git] / ltt / branches / poly / lttv / lttv / attribute.c
CommitLineData
9c312311 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Michel Dagenais
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
dc877563 18
00e74b69 19#include <string.h>
fcdf0ec2 20#include <lttv/attribute.h>
b445142a 21#include <ltt/ltt.h>
1d1df11d 22#include <ltt/compiler.h>
f32847a1 23
dc877563 24typedef union _AttributeValue {
25 int dv_int;
26 unsigned dv_uint;
27 long dv_long;
28 unsigned long dv_ulong;
29 float dv_float;
30 double dv_double;
308711e5 31 LttTime dv_time;
dc877563 32 gpointer dv_pointer;
33 char *dv_string;
ffd54a90 34 GObject *dv_gobject;
dc877563 35} AttributeValue;
36
37
38typedef struct _Attribute {
39 LttvAttributeName name;
40 LttvAttributeType type;
41 AttributeValue value;
42} Attribute;
43
44
31b6868d 45static __inline__ LttvAttributeValue address_of_value(LttvAttributeType t,
46 AttributeValue *v)
dc877563 47{
ffd54a90 48 LttvAttributeValue va;
49
50 switch(t) {
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;
00e74b69 61 case LTTV_NONE: break;
ffd54a90 62 }
63 return va;
64}
dc877563 65
dc877563 66
ffd54a90 67AttributeValue init_value(LttvAttributeType t)
68{
69 AttributeValue v;
70
71 switch(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;
00e74b69 82 case LTTV_NONE: break;
dc877563 83 }
ffd54a90 84 return v;
f32847a1 85}
86
87
dc877563 88unsigned int
89lttv_attribute_get_number(LttvAttribute *self)
90{
91 return self->attributes->len;
f32847a1 92}
93
94
dc877563 95gboolean
96lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous)
97{
98 *homogeneous = FALSE;
99 return TRUE;
f32847a1 100}
101
102
dc877563 103LttvAttributeType
104lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name,
105 LttvAttributeValue *v)
106{
107 Attribute *a;
f32847a1 108
dc877563 109 a = &g_array_index(self->attributes, Attribute, i);
110 *name = a->name;
ffd54a90 111 *v = address_of_value(a->type, &(a->value));
dc877563 112 return a->type;
f32847a1 113}
114
115
dc877563 116LttvAttributeType
117lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name,
118 LttvAttributeValue *v)
119{
120 Attribute *a;
f32847a1 121
dc877563 122 unsigned i;
f32847a1 123
ffd54a90 124 gpointer p;
125
126 p = g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
127 if(p == NULL) return LTTV_NONE;
f32847a1 128
ba576a78 129 i = GPOINTER_TO_UINT(p);
dc877563 130 i--;
131 a = &g_array_index(self->attributes, Attribute, i);
ffd54a90 132 *v = address_of_value(a->type, &(a->value));
dc877563 133 return a->type;
f32847a1 134}
135
f32847a1 136
dc877563 137LttvAttributeValue
138lttv_attribute_add(LttvAttribute *self, LttvAttributeName name,
139 LttvAttributeType t)
140{
141 unsigned i;
f32847a1 142
dc877563 143 Attribute a, *pa;
f32847a1 144
ffd54a90 145 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
dc877563 146 if(i != 0) g_error("duplicate entry in attribute table");
f32847a1 147
ffd54a90 148 a.name = name;
149 a.type = t;
150 a.value = init_value(t);
dc877563 151 g_array_append_val(self->attributes, a);
152 i = self->attributes->len - 1;
ffd54a90 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));
f32847a1 157}
158
159
dc877563 160/* Remove an attribute */
f32847a1 161
dc877563 162void
163lttv_attribute_remove(LttvAttribute *self, unsigned i)
f32847a1 164{
dc877563 165 Attribute *a;
f32847a1 166
dc877563 167 a = &g_array_index(self->attributes, Attribute, i);
f32847a1 168
c47a6dc6 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);
172
dc877563 173 /* Remove the array element and its entry in the name index */
f32847a1 174
ffd54a90 175 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
dc877563 176 g_array_remove_index_fast(self->attributes, i);
f32847a1 177
dc877563 178 /* The element used to replace the removed element has its index entry
179 all wrong now. Reinsert it with its new position. */
f32847a1 180
1d1df11d 181 if(likely(self->attributes->len != i)){
c6bc9cb9 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));
184 }
f32847a1 185}
186
dc877563 187void
188lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name)
189{
190 unsigned i;
f32847a1 191
ffd54a90 192 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
1d1df11d 193 if(unlikely(i == 0)) g_error("remove by name non existent attribute");
f32847a1 194
dc877563 195 lttv_attribute_remove(self, i - 1);
f32847a1 196}
197
dc877563 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. */
f32847a1 202
b445142a 203/*CHECK*/LttvAttribute*
204lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name)
f32847a1 205{
dc877563 206 unsigned i;
f32847a1 207
dc877563 208 Attribute a;
f32847a1 209
dc877563 210 LttvAttribute *new;
a43d67ba 211
ffd54a90 212 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
1d1df11d 213 if(likely(i != 0)) {
dc877563 214 a = g_array_index(self->attributes, Attribute, i - 1);
1d1df11d 215 if(likely(a.type == LTTV_GOBJECT && LTTV_IS_IATTRIBUTE(a.value.dv_gobject))) {
b445142a 216 return LTTV_ATTRIBUTE(a.value.dv_gobject);
dc877563 217 }
218 else return NULL;
f32847a1 219 }
ffd54a90 220 new = g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
221 *(lttv_attribute_add(self, name, LTTV_GOBJECT).v_gobject) = G_OBJECT(new);
b445142a 222 return (LttvAttribute *)new;
f32847a1 223}
224
dc877563 225gboolean
226lttv_attribute_find(LttvAttribute *self, LttvAttributeName name,
227 LttvAttributeType t, LttvAttributeValue *v)
f32847a1 228{
dc877563 229 unsigned i;
f32847a1 230
dc877563 231 Attribute *a;
f32847a1 232
ffd54a90 233 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
1d1df11d 234 if(likely(i != 0)) {
dc877563 235 a = &g_array_index(self->attributes, Attribute, i - 1);
1d1df11d 236 if(unlikely(a->type != t)) return FALSE;
ffd54a90 237 *v = address_of_value(t, &(a->value));
dc877563 238 return TRUE;
239 }
f32847a1 240
dc877563 241 *v = lttv_attribute_add(self, name, t);
242 return TRUE;
f32847a1 243}
244
f32847a1 245
c47a6dc6 246/*void lttv_attribute_recursive_free(LttvAttribute *self)
b445142a 247{
248 int i, nb;
249
250 Attribute *a;
251
252 nb = self->attributes->len;
253
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));
258 }
259 }
260 g_object_unref(self);
c47a6dc6 261}*/
b445142a 262
263
264void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src)
265{
266 int i, nb;
267
268 Attribute *a;
269
270 LttvAttributeValue value;
271
272 nb = src->attributes->len;
273
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));
280 }
281 else {
282 g_assert(lttv_attribute_find(dest, a->name, a->type, &value));
283 switch(a->type) {
c47a6dc6 284 case LTTV_INT:
b445142a 285 *value.v_int += a->value.dv_int;
286 break;
287 case LTTV_UINT:
288 *value.v_uint += a->value.dv_uint;
289 break;
290 case LTTV_LONG:
291 *value.v_long += a->value.dv_long;
292 break;
293 case LTTV_ULONG:
294 *value.v_ulong += a->value.dv_ulong;
295 break;
296 case LTTV_FLOAT:
297 *value.v_float += a->value.dv_float;
298 break;
299 case LTTV_DOUBLE:
300 *value.v_double += a->value.dv_double;
301 break;
302 case LTTV_TIME:
308711e5 303 *value.v_time = ltt_time_add(*value.v_time, a->value.dv_time);
b445142a 304 break;
305 case LTTV_POINTER:
306 break;
307 case LTTV_STRING:
308 break;
309 case LTTV_GOBJECT:
310 break;
311 case LTTV_NONE:
312 break;
313 }
314 }
315 }
316}
317
318
f95bc830 319static void
320print_indent(FILE *fp, int pos)
321{
322 int i;
323
324 for(i = 0 ; i < pos ; i++) putc(' ', fp);
325}
326
327
328void
329lttv_attribute_write_xml(LttvAttribute *self, FILE *fp, int pos, int indent)
330{
331 int i, nb;
332
333 Attribute *a;
334
335 nb = self->attributes->len;
336
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);
5bf80c50 341 fprintf(fp, "<ATTR NAME=\"%s\" ", g_quark_to_string(a->name));
f95bc830 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);
346 }
347 else {
348 switch(a->type) {
349 case LTTV_INT:
350 fprintf(fp, "TYPE=INT VALUE=%d/>\n", a->value.dv_int);
351 break;
352 case LTTV_UINT:
353 fprintf(fp, "TYPE=UINT VALUE=%u/>\n", a->value.dv_uint);
354 break;
355 case LTTV_LONG:
356 fprintf(fp, "TYPE=LONG VALUE=%ld/>\n", a->value.dv_long);
357 break;
358 case LTTV_ULONG:
359 fprintf(fp, "TYPE=ULONG VALUE=%lu/>\n", a->value.dv_ulong);
360 break;
361 case LTTV_FLOAT:
362 fprintf(fp, "TYPE=FLOAT VALUE=%f/>\n", a->value.dv_float);
363 break;
364 case LTTV_DOUBLE:
365 fprintf(fp, "TYPE=DOUBLE VALUE=%f/>\n", a->value.dv_double);
366 break;
367 case LTTV_TIME:
00e74b69 368 fprintf(fp, "TYPE=TIME SEC=%lu NSEC=%lu/>\n", a->value.dv_time.tv_sec,
f95bc830 369 a->value.dv_time.tv_nsec);
370 break;
371 case LTTV_POINTER:
372 fprintf(fp, "TYPE=POINTER VALUE=%p/>\n", a->value.dv_pointer);
373 break;
374 case LTTV_STRING:
375 fprintf(fp, "TYPE=STRING VALUE=\"%s\"/>\n", a->value.dv_string);
376 break;
377 case LTTV_GOBJECT:
378 fprintf(fp, "TYPE=GOBJECT VALUE=%p/>\n", a->value.dv_gobject);
379 break;
380 case LTTV_NONE:
381 fprintf(fp, "TYPE=NONE/>\n");
382 break;
383 }
384 }
385 }
386 print_indent(fp, pos);
387 fprintf(fp,"</ATTRS>\n");
388}
389
390
391void
392lttv_attribute_read_xml(LttvAttribute *self, FILE *fp)
393{
00e74b69 394 int res;
f95bc830 395
396 char buffer[256], type[10];
397
398 LttvAttributeName name;
399
400 LttvAttributeValue value;
401
402 LttvAttribute *subtree;
403
404 fscanf(fp,"<ATTRS>");
405 while(1) {
406 res = fscanf(fp, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer, type);
407 g_assert(res == 2);
408 name = g_quark_from_string(buffer);
409 if(strcmp(type, "ATTRS") == 0) {
410 fscanf(fp, ">");
411 subtree = lttv_attribute_find_subdir(self, name);
412 lttv_attribute_read_xml(subtree, fp);
413 }
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);
417 g_assert(res == 1);
418 }
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);
422 g_assert(res == 1);
423 }
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);
427 g_assert(res == 1);
428 }
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);
432 g_assert(res == 1);
433 }
434 else if(strcmp(type, "FLOAT") == 0) {
435 float d;
436 value = lttv_attribute_add(self, name, LTTV_FLOAT);
437 res = fscanf(fp, " VALUE=%f/>", &d);
438 *(value.v_float) = d;
439 g_assert(res == 1);
440 }
441 else if(strcmp(type, "DOUBLE") == 0) {
442 value = lttv_attribute_add(self, name, LTTV_DOUBLE);
00e74b69 443 res = fscanf(fp, " VALUE=%lf/>", value.v_double);
f95bc830 444 g_assert(res == 1);
445 }
446 else if(strcmp(type, "TIME") == 0) {
447 value = lttv_attribute_add(self, name, LTTV_TIME);
00e74b69 448 res = fscanf(fp, " SEC=%lu NSEC=%lu/>", &(value.v_time->tv_sec),
f95bc830 449 &(value.v_time->tv_nsec));
450 g_assert(res == 2);
451 }
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");
456 }
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);
461 g_assert(res == 1);
462 }
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");
467 }
468 else if(strcmp(type, "NONE") == 0) {
469 value = lttv_attribute_add(self, name, LTTV_NONE);
470 fscanf(fp, "/>");
471 }
472 else g_error("Unknown type to read");
473 }
474 fscanf(fp,"</ATTRS>");
475}
476
3e67c985 477static LttvAttribute *
478new_attribute (LttvAttribute *self)
479{
480 return g_object_new(LTTV_ATTRIBUTE_TYPE, NULL);
481}
482
f95bc830 483
dc877563 484static void
485attribute_interface_init (gpointer g_iface, gpointer iface_data)
f32847a1 486{
dc877563 487 LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface;
f32847a1 488
3e67c985 489 klass->new_attribute = (LttvIAttribute* (*) (LttvIAttribute *self))
490 new_attribute;
491
dc877563 492 klass->get_number = (unsigned int (*) (LttvIAttribute *self))
493 lttv_attribute_get_number;
f32847a1 494
dc877563 495 klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous))
496 lttv_attribute_named;
f32847a1 497
dc877563 498 klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i,
499 LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get;
f32847a1 500
dc877563 501 klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self,
502 LttvAttributeName name, LttvAttributeValue *v))
503 lttv_attribute_get_by_name;
f32847a1 504
dc877563 505 klass->add = (LttvAttributeValue (*) (LttvIAttribute *self,
506 LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add;
f32847a1 507
dc877563 508 klass->remove = (void (*) (LttvIAttribute *self, unsigned i))
509 lttv_attribute_remove;
f32847a1 510
dc877563 511 klass->remove_by_name = (void (*) (LttvIAttribute *self,
512 LttvAttributeName name)) lttv_attribute_remove_by_name;
f32847a1 513
b445142a 514 klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
515 LttvAttributeName name)) lttv_attribute_find_subdir;
5e2c04a2 516
f32847a1 517}
518
dc877563 519static void
520attribute_instance_init (GTypeInstance *instance, gpointer g_class)
f32847a1 521{
dc877563 522 LttvAttribute *self = (LttvAttribute *)instance;
6843100a 523 self->names = g_hash_table_new(g_direct_hash,
524 g_direct_equal);
ffd54a90 525 self->attributes = g_array_new(FALSE, FALSE, sizeof(Attribute));
f32847a1 526}
527
f32847a1 528
dc877563 529static void
530attribute_finalize (LttvAttribute *self)
f32847a1 531{
4d39be09 532 guint i;
2a2fa4f0 533 g_log(G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "attribute_finalize()");
4d39be09 534
535 for(i=0;i<self->attributes->len;i++) {
536 lttv_attribute_remove(self, i);
537 }
538
539 g_hash_table_destroy(self->names);
dc877563 540 g_array_free(self->attributes, TRUE);
f32847a1 541}
542
f32847a1 543
dc877563 544static void
545attribute_class_init (LttvAttributeClass *klass)
f32847a1 546{
dc877563 547 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
3e67c985 548
ffd54a90 549 gobject_class->finalize = (void (*)(GObject *self))attribute_finalize;
f32847a1 550}
551
ffd54a90 552GType
553lttv_attribute_get_type (void)
554{
555 static GType type = 0;
556 if (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),
565 0, /* n_preallocs */
00e74b69 566 (GInstanceInitFunc) attribute_instance_init, /* instance_init */
567 NULL /* value handling */
ffd54a90 568 };
569
570 static const GInterfaceInfo iattribute_info = {
571 (GInterfaceInitFunc) attribute_interface_init, /* interface_init */
572 NULL, /* interface_finalize */
573 NULL /* interface_data */
574 };
575
576 type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info,
577 0);
578 g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info);
579 }
580 return type;
581}
582
583
This page took 0.058347 seconds and 4 git commands to generate.