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