2005-02-17 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / glib / dbus-gidl.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-gidl.c data structure describing an interface, to be generated from IDL
3  *             or something
4  *
5  * Copyright (C) 2003, 2005  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include "dbus-gidl.h"
26
27 #ifndef DOXYGEN_SHOULD_SKIP_THIS
28
29 struct BaseInfo
30 {
31   unsigned int refcount : 28;
32   unsigned int type     : 4;
33   char *name;
34 };
35
36 struct NodeInfo
37 {
38   BaseInfo base;
39   GSList *interfaces;
40   GSList *nodes;
41 };
42
43 struct InterfaceInfo
44 {
45   BaseInfo base;
46   GHashTable *bindings;
47   /* Since we have BaseInfo now these could be one list */
48   GSList *methods;
49   GSList *signals;
50   GSList *properties;
51 };
52
53 struct MethodInfo
54 {
55   BaseInfo base;
56   GHashTable *bindings;
57   GSList *args;
58 };
59
60 struct SignalInfo
61 {
62   BaseInfo base;
63   GSList *args;
64 };
65
66 struct PropertyInfo
67 {
68   BaseInfo base;
69   int type;
70   PropertyAccessFlags access;
71 };
72
73 struct ArgInfo
74 {
75   BaseInfo base;
76   int type;
77   ArgDirection direction;
78 };
79
80 static void
81 get_hash_key (gpointer key, gpointer value, gpointer data)
82 {
83   GSList **list = data;
84   *list = g_slist_prepend (*list, key);
85 }
86
87 static GSList *
88 get_hash_keys (GHashTable *table)
89 {
90   GSList *ret = NULL;
91
92   g_hash_table_foreach (table, get_hash_key, &ret);
93
94   return ret;
95 }
96
97 BaseInfo *
98 base_info_ref (BaseInfo *info)
99 {
100   g_return_val_if_fail (info != NULL, NULL);
101   g_return_val_if_fail (info->refcount > 0, NULL);
102   
103   info->refcount += 1;
104
105   return info;
106 }
107
108 static void
109 base_info_free (void *ptr)
110 {
111   BaseInfo *info;
112
113   info = ptr;
114   
115   g_free (info->name);
116   g_free (info);
117 }
118
119 void
120 base_info_unref (BaseInfo *info)
121 {
122   g_return_if_fail (info != NULL);
123   g_return_if_fail (info->refcount > 0);
124   
125   /* This is sort of bizarre, BaseInfo was tacked on later */
126
127   switch (info->type)
128     {
129     case INFO_TYPE_NODE:
130       node_info_unref ((NodeInfo*) info);
131       break;
132     case INFO_TYPE_INTERFACE:
133       interface_info_unref ((InterfaceInfo*) info);
134       break;
135     case INFO_TYPE_SIGNAL:
136       signal_info_unref ((SignalInfo*) info);
137       break;
138     case INFO_TYPE_METHOD:
139       method_info_unref ((MethodInfo*) info);
140       break;
141     case INFO_TYPE_PROPERTY:
142       property_info_unref ((PropertyInfo*) info);
143       break;
144     case INFO_TYPE_ARG:
145       arg_info_unref ((ArgInfo*) info);
146       break;
147     }
148 }
149
150 InfoType
151 base_info_get_type (BaseInfo      *info)
152 {
153   return info->type;
154 }
155
156 const char*
157 base_info_get_name (BaseInfo *info)
158 {
159   return info->name;
160 }
161
162 void
163 base_info_set_name (BaseInfo      *info,
164                     const char    *name)
165 {
166   char *old;
167
168   old = info->name;
169   info->name = g_strdup (name);
170   g_free (old);
171 }
172
173 GType
174 base_info_get_gtype (void)
175 {
176   static GType our_type = 0;
177   
178   if (our_type == 0)
179     our_type = g_boxed_type_register_static ("BaseInfo",
180                                              (GBoxedCopyFunc) base_info_ref,
181                                              (GBoxedFreeFunc) base_info_unref);
182
183   return our_type;
184 }
185
186 static void
187 free_interface_list (GSList **interfaces_p)
188 {
189   GSList *tmp;
190   tmp = *interfaces_p;
191   while (tmp != NULL)
192     {
193       interface_info_unref (tmp->data);
194       tmp = tmp->next;
195     }
196   g_slist_free (*interfaces_p);
197   *interfaces_p = NULL;
198 }
199
200 static void
201 free_node_list (GSList **nodes_p)
202 {
203   GSList *tmp;
204   tmp = *nodes_p;
205   while (tmp != NULL)
206     {
207       node_info_unref (tmp->data);
208       tmp = tmp->next;
209     }
210   g_slist_free (*nodes_p);
211   *nodes_p = NULL;
212 }
213
214 static void
215 free_method_list (GSList **methods_p)
216 {
217   GSList *tmp;
218   tmp = *methods_p;
219   while (tmp != NULL)
220     {
221       method_info_unref (tmp->data);
222       tmp = tmp->next;
223     }
224   g_slist_free (*methods_p);
225   *methods_p = NULL;
226 }
227
228 static void
229 free_signal_list (GSList **signals_p)
230 {
231   GSList *tmp;
232   tmp = *signals_p;
233   while (tmp != NULL)
234     {
235       signal_info_unref (tmp->data);
236       tmp = tmp->next;
237     }
238   g_slist_free (*signals_p);
239   *signals_p = NULL;
240 }
241
242 static void
243 free_property_list (GSList **props_p)
244 {
245   GSList *tmp;
246   tmp = *props_p;
247   while (tmp != NULL)
248     {
249       property_info_unref (tmp->data);
250       tmp = tmp->next;
251     }
252   g_slist_free (*props_p);
253   *props_p = NULL;
254 }
255
256 NodeInfo*
257 node_info_new (const char *name)
258 {
259   NodeInfo *info;
260
261   /* name can be NULL */
262   
263   info = g_new0 (NodeInfo, 1);
264   info->base.refcount = 1;
265   info->base.name = g_strdup (name);
266   info->base.type = INFO_TYPE_NODE;
267   
268   return info;
269 }
270
271 NodeInfo *
272 node_info_ref (NodeInfo *info)
273 {
274   info->base.refcount += 1;
275
276   return info;
277 }
278
279 void
280 node_info_unref (NodeInfo *info)
281 {
282   info->base.refcount -= 1;
283   if (info->base.refcount == 0)
284     {
285       free_interface_list (&info->interfaces);
286       free_node_list (&info->nodes);
287       base_info_free (info);
288     }
289 }
290
291 const char*
292 node_info_get_name (NodeInfo *info)
293 {
294   return info->base.name;
295 }
296
297 GSList*
298 node_info_get_interfaces (NodeInfo *info)
299 {
300   return info->interfaces;
301 }
302
303 void
304 node_info_add_interface (NodeInfo *info,
305                          InterfaceInfo    *interface)
306 {
307   interface_info_ref (interface);
308   info->interfaces = g_slist_append (info->interfaces, interface);
309 }
310
311 GSList*
312 node_info_get_nodes (NodeInfo *info)
313 {
314   return info->nodes;
315 }
316
317 void
318 node_info_add_node (NodeInfo *info,
319                     NodeInfo *node)
320 {
321   node_info_ref (node);
322   info->nodes = g_slist_append (info->nodes, node);
323 }
324
325 void
326 node_info_replace_node (NodeInfo            *info,
327                         NodeInfo            *old_child,
328                         NodeInfo            *new_child)
329 {
330   GSList *link;
331
332   node_info_ref (new_child); /* before unref old_child in case they are the same */
333   link = g_slist_find (info->nodes, old_child);
334   g_assert (link != NULL);
335   node_info_unref (old_child);
336   link->data = new_child;
337 }
338
339 InterfaceInfo*
340 interface_info_new (const char *name)
341 {
342   InterfaceInfo *info;
343
344   info = g_new0 (InterfaceInfo, 1);
345   info->base.refcount = 1;
346   info->base.name = g_strdup (name);
347   info->base.type = INFO_TYPE_INTERFACE;
348   info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
349                                           (GDestroyNotify) g_free,
350                                           (GDestroyNotify) g_free);
351   
352   return info;
353 }
354
355 InterfaceInfo *
356 interface_info_ref (InterfaceInfo *info)
357 {
358   info->base.refcount += 1;
359
360   return info;
361 }
362
363 void
364 interface_info_unref (InterfaceInfo *info)
365 {
366   info->base.refcount -= 1;
367   if (info->base.refcount == 0)
368     {
369       g_hash_table_destroy (info->bindings);
370       free_method_list (&info->methods);
371       free_signal_list (&info->signals);
372       free_property_list (&info->properties);
373       base_info_free (info);
374     }
375 }
376
377 const char*
378 interface_info_get_name (InterfaceInfo *info)
379 {
380   return info->base.name;
381 }
382
383 GSList *
384 interface_info_get_binding_names (InterfaceInfo *info)
385 {
386   return get_hash_keys (info->bindings);
387 }
388
389 const char*
390 interface_info_get_binding_name (InterfaceInfo *info,
391                                  const char    *binding_type)
392 {
393   return g_hash_table_lookup (info->bindings, binding_type);
394 }
395
396 GSList*
397 interface_info_get_methods (InterfaceInfo *info)
398 {
399   return info->methods;
400 }
401
402 GSList*
403 interface_info_get_signals (InterfaceInfo *info)
404 {
405   return info->signals;
406 }
407
408 GSList*
409 interface_info_get_properties (InterfaceInfo *info)
410 {
411   return info->properties;
412 }
413
414 void
415 interface_info_set_binding_name (InterfaceInfo *info,
416                                  const char    *binding_type,
417                                  const char    *bound_name)
418 {
419   g_hash_table_insert (info->bindings,
420                        g_strdup (binding_type),
421                        g_strdup (bound_name));
422 }
423
424 void
425 interface_info_add_method (InterfaceInfo *info,
426                            MethodInfo    *method)
427 {
428   method_info_ref (method);
429   info->methods = g_slist_append (info->methods, method);
430 }
431
432 void
433 interface_info_add_signal (InterfaceInfo *info,
434                            SignalInfo    *signal)
435 {
436   signal_info_ref (signal);
437   info->signals = g_slist_append (info->signals, signal);
438 }
439
440 void
441 interface_info_add_property (InterfaceInfo *info,
442                              PropertyInfo  *property)
443 {
444   property_info_ref (property);
445   info->properties = g_slist_append (info->properties, property);
446 }
447
448 static void
449 free_arg_list (GSList **args_p)
450 {
451   GSList *tmp;
452   tmp = *args_p;
453   while (tmp != NULL)
454     {
455       ArgInfo *ai = tmp->data;
456       g_assert (ai->base.type == INFO_TYPE_ARG);
457       arg_info_unref (tmp->data);
458       tmp = tmp->next;
459     }
460   g_slist_free (*args_p);
461   *args_p = NULL;
462 }
463
464 MethodInfo*
465 method_info_new (const char *name)
466 {
467   MethodInfo *info;
468
469   info = g_new0 (MethodInfo, 1);
470   info->base.refcount = 1;
471   info->base.name = g_strdup (name);
472   info->base.type = INFO_TYPE_METHOD;
473   info->bindings = g_hash_table_new_full (g_str_hash, g_str_equal,
474                                           (GDestroyNotify) g_free,
475                                           (GDestroyNotify) g_free);
476   
477   return info;
478 }
479
480 MethodInfo *
481 method_info_ref (MethodInfo *info)
482 {
483   info->base.refcount += 1;
484
485   return info;
486 }
487
488 void
489 method_info_unref (MethodInfo *info)
490 {
491   info->base.refcount -= 1;
492   if (info->base.refcount == 0)
493     {
494       g_hash_table_destroy (info->bindings);
495       free_arg_list (&info->args);
496       base_info_free (info);
497     }
498 }
499
500 const char*
501 method_info_get_name (MethodInfo *info)
502 {
503   return info->base.name;
504 }
505
506 GSList *
507 method_info_get_binding_names (MethodInfo *info)
508 {
509   return get_hash_keys (info->bindings);
510 }
511
512 const char*
513 method_info_get_binding_name (MethodInfo *info,
514                               const char *binding_type)
515 {
516   return g_hash_table_lookup (info->bindings, binding_type);
517 }
518
519 GSList*
520 method_info_get_args (MethodInfo *info)
521 {
522   return info->args;
523 }
524
525 int
526 method_info_get_n_args (MethodInfo *info)
527 {
528   return g_slist_length (info->args);
529 }
530
531 static int
532 args_sort_by_direction (const void *a,
533                         const void *b)
534 {
535   const ArgInfo *arg_a = a;
536   const ArgInfo *arg_b = b;
537
538   if (arg_a->direction == arg_b->direction)
539     return 0;
540   else if (arg_a->direction == ARG_IN)
541     return -1; /* in is less than out */
542   else
543     return 1;
544 }                  
545
546 void
547 method_info_set_binding_name (MethodInfo  *info,
548                               const char  *binding_type,
549                               const char  *bound_name)
550 {
551   g_hash_table_insert (info->bindings,
552                        g_strdup (binding_type),
553                        g_strdup (bound_name));
554 }
555
556 void
557 method_info_add_arg (MethodInfo    *info,
558                      ArgInfo       *arg)
559 {
560   arg_info_ref (arg);
561   info->args = g_slist_append (info->args, arg);
562
563   /* Keep "in" args sorted before "out" and otherwise maintain
564    * stable order (g_slist_sort is stable, at least in sufficiently
565    * new glib)
566    */
567   info->args = g_slist_sort (info->args, args_sort_by_direction);
568 }
569
570 SignalInfo*
571 signal_info_new (const char *name)
572 {
573   SignalInfo *info;
574
575   info = g_new0 (SignalInfo, 1);
576   info->base.refcount = 1;
577   info->base.name = g_strdup (name);
578   info->base.type = INFO_TYPE_SIGNAL;
579   
580   return info;
581 }
582
583 SignalInfo *
584 signal_info_ref (SignalInfo *info)
585 {
586   info->base.refcount += 1;
587
588   return info;
589 }
590
591 void
592 signal_info_unref (SignalInfo *info)
593 {
594   info->base.refcount -= 1;
595   if (info->base.refcount == 0)
596     {
597       free_arg_list (&info->args);
598       base_info_free (info);
599     }
600 }
601
602 const char*
603 signal_info_get_name (SignalInfo *info)
604 {
605   return info->base.name;
606 }
607
608 GSList*
609 signal_info_get_args (SignalInfo *info)
610 {
611   return info->args;
612 }
613
614 int
615 signal_info_get_n_args (SignalInfo *info)
616 {
617   return g_slist_length (info->args);
618 }
619
620 void
621 signal_info_add_arg (SignalInfo    *info,
622                      ArgInfo       *arg)
623 {
624   g_assert (arg->direction == ARG_OUT);
625   
626   arg_info_ref (arg);
627   info->args = g_slist_append (info->args, arg);
628   
629   /* signal args don't need sorting since only "out" is allowed */
630 }
631
632 PropertyInfo*
633 property_info_new (const char          *name,
634                    int                  type,
635                    PropertyAccessFlags  access)
636 {
637   PropertyInfo *info;
638
639   info = g_new0 (PropertyInfo, 1);
640   info->base.refcount = 1;
641   info->base.name = g_strdup (name);
642   info->base.type = INFO_TYPE_PROPERTY;
643
644   info->type = type;
645   info->access = access;
646   
647   return info;
648 }
649
650 PropertyInfo*
651 property_info_ref (PropertyInfo *info)
652 {
653   info->base.refcount += 1;
654   
655   return info;
656 }
657
658 void
659 property_info_unref (PropertyInfo *info)
660 {
661   info->base.refcount -= 1;
662   if (info->base.refcount == 0)
663     {
664       base_info_free (info);
665     }
666 }
667
668 const char*
669 property_info_get_name (PropertyInfo *info)
670 {
671   return info->base.name;
672 }
673
674 int
675 property_info_get_type (PropertyInfo *info)
676 {
677   return info->type;
678 }
679
680 PropertyAccessFlags
681 property_info_get_access (PropertyInfo *info)
682 {
683   return info->access;
684 }
685
686 ArgInfo*
687 arg_info_new (const char  *name,
688               ArgDirection direction,
689               int          type)
690 {
691   ArgInfo *info;
692
693   info = g_new0 (ArgInfo, 1);
694   info->base.refcount = 1;
695   info->base.type = INFO_TYPE_ARG;
696   
697   /* name can be NULL */
698   info->base.name = g_strdup (name);
699   info->direction = direction;
700   info->type = type;
701
702   return info;
703 }
704
705 ArgInfo *
706 arg_info_ref (ArgInfo *info)
707 {
708   info->base.refcount += 1;
709
710   return info;
711 }
712
713 void
714 arg_info_unref (ArgInfo *info)
715 {
716   info->base.refcount -= 1;
717   if (info->base.refcount == 0)
718     {
719       base_info_free (info);
720     }
721 }
722 const char*
723 arg_info_get_name (ArgInfo *info)
724 {
725   return info->base.name;
726 }
727
728 int
729 arg_info_get_type (ArgInfo *info)
730 {
731   return info->type;
732 }
733
734 ArgDirection
735 arg_info_get_direction (ArgInfo *info)
736 {
737   return info->direction;
738 }
739
740 #ifdef DBUS_BUILD_TESTS
741
742 /**
743  * @ingroup DBusGIDL
744  * Unit test for GLib IDL internals
745  * @returns #TRUE on success.
746  */
747 gboolean
748 _dbus_gidl_test (void)
749 {
750
751   return TRUE;
752 }
753
754 #endif /* DBUS_BUILD_TESTS */
755
756 #endif /* DOXYGEN_SHOULD_SKIP_THIS */