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