Add reference counts to state and stats saved attributes. This way, the
[lttv.git] / ltt / branches / poly / lttv / main / attribute.c
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 */
18
19 #include <lttv/attribute.h>
20 #include <ltt/ltt.h>
21
22 typedef union _AttributeValue {
23 int dv_int;
24 unsigned dv_uint;
25 long dv_long;
26 unsigned long dv_ulong;
27 float dv_float;
28 double dv_double;
29 LttTime dv_time;
30 gpointer dv_pointer;
31 char *dv_string;
32 GObject *dv_gobject;
33 } AttributeValue;
34
35
36 typedef struct _Attribute {
37 LttvAttributeName name;
38 LttvAttributeType type;
39 AttributeValue value;
40 } Attribute;
41
42
43 LttvAttributeValue address_of_value(LttvAttributeType t, AttributeValue *v)
44 {
45 LttvAttributeValue va;
46
47 switch(t) {
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;
58 }
59 return va;
60 }
61
62
63 AttributeValue init_value(LttvAttributeType t)
64 {
65 AttributeValue v;
66
67 switch(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;
78 }
79 return v;
80 }
81
82
83 unsigned int
84 lttv_attribute_get_number(LttvAttribute *self)
85 {
86 return self->attributes->len;
87 }
88
89
90 gboolean
91 lttv_attribute_named(LttvAttribute *self, gboolean *homogeneous)
92 {
93 *homogeneous = FALSE;
94 return TRUE;
95 }
96
97
98 LttvAttributeType
99 lttv_attribute_get(LttvAttribute *self, unsigned i, LttvAttributeName *name,
100 LttvAttributeValue *v)
101 {
102 Attribute *a;
103
104 a = &g_array_index(self->attributes, Attribute, i);
105 *name = a->name;
106 *v = address_of_value(a->type, &(a->value));
107 return a->type;
108 }
109
110
111 LttvAttributeType
112 lttv_attribute_get_by_name(LttvAttribute *self, LttvAttributeName name,
113 LttvAttributeValue *v)
114 {
115 Attribute *a;
116
117 unsigned i;
118
119 gpointer p;
120
121 p = g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
122 if(p == NULL) return LTTV_NONE;
123
124 i = GPOINTER_TO_UINT(p);
125 i--;
126 a = &g_array_index(self->attributes, Attribute, i);
127 *v = address_of_value(a->type, &(a->value));
128 return a->type;
129 }
130
131
132 LttvAttributeValue
133 lttv_attribute_add(LttvAttribute *self, LttvAttributeName name,
134 LttvAttributeType t)
135 {
136 unsigned i;
137
138 Attribute a, *pa;
139
140 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
141 if(i != 0) g_error("duplicate entry in attribute table");
142
143 a.name = name;
144 a.type = t;
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));
152 }
153
154
155 /* Remove an attribute */
156
157 void
158 lttv_attribute_remove(LttvAttribute *self, unsigned i)
159 {
160 Attribute *a;
161
162 a = &g_array_index(self->attributes, Attribute, i);
163
164 /* Remove the array element and its entry in the name index */
165
166 g_hash_table_remove(self->names, GUINT_TO_POINTER(a->name));
167 g_array_remove_index_fast(self->attributes, i);
168
169 /* The element used to replace the removed element has its index entry
170 all wrong now. Reinsert it with its new position. */
171
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));
175 }
176 }
177
178 void
179 lttv_attribute_remove_by_name(LttvAttribute *self, LttvAttributeName name)
180 {
181 unsigned i;
182
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");
185
186 lttv_attribute_remove(self, i - 1);
187 }
188
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. */
193
194 /*CHECK*/LttvAttribute*
195 lttv_attribute_find_subdir(LttvAttribute *self, LttvAttributeName name)
196 {
197 unsigned i;
198
199 Attribute a;
200
201 LttvAttribute *new;
202
203 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
204 if(i != 0) {
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);
208 }
209 else return NULL;
210 }
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;
214 }
215
216 gboolean
217 lttv_attribute_find(LttvAttribute *self, LttvAttributeName name,
218 LttvAttributeType t, LttvAttributeValue *v)
219 {
220 unsigned i;
221
222 Attribute *a;
223
224 i = (unsigned)g_hash_table_lookup(self->names, GUINT_TO_POINTER(name));
225 if(i != 0) {
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));
229 return TRUE;
230 }
231
232 *v = lttv_attribute_add(self, name, t);
233 return TRUE;
234 }
235
236
237 void lttv_attribute_recursive_free(LttvAttribute *self)
238 {
239 int i, nb;
240
241 Attribute *a;
242
243 nb = self->attributes->len;
244
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));
249 }
250 }
251 g_object_unref(self);
252 }
253
254
255 void lttv_attribute_recursive_add(LttvAttribute *dest, LttvAttribute *src)
256 {
257 int i, nb;
258
259 Attribute *a;
260
261 LttvAttributeValue value;
262
263 nb = src->attributes->len;
264
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));
271 }
272 else {
273 g_assert(lttv_attribute_find(dest, a->name, a->type, &value));
274 switch(a->type) {
275 case LTTV_INT:
276 *value.v_int += a->value.dv_int;
277 break;
278 case LTTV_UINT:
279 *value.v_uint += a->value.dv_uint;
280 break;
281 case LTTV_LONG:
282 *value.v_long += a->value.dv_long;
283 break;
284 case LTTV_ULONG:
285 *value.v_ulong += a->value.dv_ulong;
286 break;
287 case LTTV_FLOAT:
288 *value.v_float += a->value.dv_float;
289 break;
290 case LTTV_DOUBLE:
291 *value.v_double += a->value.dv_double;
292 break;
293 case LTTV_TIME:
294 *value.v_time = ltt_time_add(*value.v_time, a->value.dv_time);
295 break;
296 case LTTV_POINTER:
297 break;
298 case LTTV_STRING:
299 break;
300 case LTTV_GOBJECT:
301 break;
302 case LTTV_NONE:
303 break;
304 }
305 }
306 }
307 }
308
309
310 static void
311 print_indent(FILE *fp, int pos)
312 {
313 int i;
314
315 for(i = 0 ; i < pos ; i++) putc(' ', fp);
316 }
317
318
319 void
320 lttv_attribute_write_xml(LttvAttribute *self, FILE *fp, int pos, int indent)
321 {
322 int i, nb;
323
324 Attribute *a;
325
326 nb = self->attributes->len;
327
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);
337 }
338 else {
339 switch(a->type) {
340 case LTTV_INT:
341 fprintf(fp, "TYPE=INT VALUE=%d/>\n", a->value.dv_int);
342 break;
343 case LTTV_UINT:
344 fprintf(fp, "TYPE=UINT VALUE=%u/>\n", a->value.dv_uint);
345 break;
346 case LTTV_LONG:
347 fprintf(fp, "TYPE=LONG VALUE=%ld/>\n", a->value.dv_long);
348 break;
349 case LTTV_ULONG:
350 fprintf(fp, "TYPE=ULONG VALUE=%lu/>\n", a->value.dv_ulong);
351 break;
352 case LTTV_FLOAT:
353 fprintf(fp, "TYPE=FLOAT VALUE=%f/>\n", a->value.dv_float);
354 break;
355 case LTTV_DOUBLE:
356 fprintf(fp, "TYPE=DOUBLE VALUE=%f/>\n", a->value.dv_double);
357 break;
358 case LTTV_TIME:
359 fprintf(fp, "TYPE=TIME SEC=%u NSEC=%u/>\n", a->value.dv_time.tv_sec,
360 a->value.dv_time.tv_nsec);
361 break;
362 case LTTV_POINTER:
363 fprintf(fp, "TYPE=POINTER VALUE=%p/>\n", a->value.dv_pointer);
364 break;
365 case LTTV_STRING:
366 fprintf(fp, "TYPE=STRING VALUE=\"%s\"/>\n", a->value.dv_string);
367 break;
368 case LTTV_GOBJECT:
369 fprintf(fp, "TYPE=GOBJECT VALUE=%p/>\n", a->value.dv_gobject);
370 break;
371 case LTTV_NONE:
372 fprintf(fp, "TYPE=NONE/>\n");
373 break;
374 }
375 }
376 }
377 print_indent(fp, pos);
378 fprintf(fp,"</ATTRS>\n");
379 }
380
381
382 void
383 lttv_attribute_read_xml(LttvAttribute *self, FILE *fp)
384 {
385 int i, nb, res;
386
387 Attribute *a;
388
389 char buffer[256], type[10];
390
391 LttvAttributeName name;
392
393 LttvAttributeValue value;
394
395 LttvAttribute *subtree;
396
397 fscanf(fp,"<ATTRS>");
398 while(1) {
399 res = fscanf(fp, "<ATTR NAME=\"%256[^\"]\" TYPE=%10[^ >]", buffer, type);
400 g_assert(res == 2);
401 name = g_quark_from_string(buffer);
402 if(strcmp(type, "ATTRS") == 0) {
403 fscanf(fp, ">");
404 subtree = lttv_attribute_find_subdir(self, name);
405 lttv_attribute_read_xml(subtree, fp);
406 }
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);
410 g_assert(res == 1);
411 }
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);
415 g_assert(res == 1);
416 }
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);
420 g_assert(res == 1);
421 }
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);
425 g_assert(res == 1);
426 }
427 else if(strcmp(type, "FLOAT") == 0) {
428 float d;
429 value = lttv_attribute_add(self, name, LTTV_FLOAT);
430 res = fscanf(fp, " VALUE=%f/>", &d);
431 *(value.v_float) = d;
432 g_assert(res == 1);
433 }
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);
437 g_assert(res == 1);
438 }
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));
443 g_assert(res == 2);
444 }
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");
449 }
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);
454 g_assert(res == 1);
455 }
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");
460 }
461 else if(strcmp(type, "NONE") == 0) {
462 value = lttv_attribute_add(self, name, LTTV_NONE);
463 fscanf(fp, "/>");
464 }
465 else g_error("Unknown type to read");
466 }
467 fscanf(fp,"</ATTRS>");
468 }
469
470
471 static void
472 attribute_interface_init (gpointer g_iface, gpointer iface_data)
473 {
474 LttvIAttributeClass *klass = (LttvIAttributeClass *)g_iface;
475
476 klass->get_number = (unsigned int (*) (LttvIAttribute *self))
477 lttv_attribute_get_number;
478
479 klass->named = (gboolean (*) (LttvIAttribute *self, gboolean *homogeneous))
480 lttv_attribute_named;
481
482 klass->get = (LttvAttributeType (*) (LttvIAttribute *self, unsigned i,
483 LttvAttributeName *name, LttvAttributeValue *v)) lttv_attribute_get;
484
485 klass->get_by_name = (LttvAttributeType (*) (LttvIAttribute *self,
486 LttvAttributeName name, LttvAttributeValue *v))
487 lttv_attribute_get_by_name;
488
489 klass->add = (LttvAttributeValue (*) (LttvIAttribute *self,
490 LttvAttributeName name, LttvAttributeType t)) lttv_attribute_add;
491
492 klass->remove = (void (*) (LttvIAttribute *self, unsigned i))
493 lttv_attribute_remove;
494
495 klass->remove_by_name = (void (*) (LttvIAttribute *self,
496 LttvAttributeName name)) lttv_attribute_remove_by_name;
497
498 klass->find_subdir = (LttvIAttribute* (*) (LttvIAttribute *self,
499 LttvAttributeName name)) lttv_attribute_find_subdir;
500 }
501
502
503 static void
504 attribute_instance_init (GTypeInstance *instance, gpointer g_class)
505 {
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));
509 }
510
511
512 static void
513 attribute_finalize (LttvAttribute *self)
514 {
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));
520 }
521
522
523 static void
524 attribute_class_init (LttvAttributeClass *klass)
525 {
526 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
527
528 gobject_class->finalize = (void (*)(GObject *self))attribute_finalize;
529 }
530
531 GType
532 lttv_attribute_get_type (void)
533 {
534 static GType type = 0;
535 if (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),
544 0, /* n_preallocs */
545 (GInstanceInitFunc) attribute_instance_init /* instance_init */
546 };
547
548 static const GInterfaceInfo iattribute_info = {
549 (GInterfaceInitFunc) attribute_interface_init, /* interface_init */
550 NULL, /* interface_finalize */
551 NULL /* interface_data */
552 };
553
554 type = g_type_register_static (G_TYPE_OBJECT, "LttvAttributeType", &info,
555 0);
556 g_type_add_interface_static (type, LTTV_IATTRIBUTE_TYPE, &iattribute_info);
557 }
558 return type;
559 }
560
561
This page took 0.057081 seconds and 4 git commands to generate.