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