2004-05-31 Havoc Pennington <hp@redhat.com>
[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  Red Hat, Inc.
6  *
7  * Licensed under the Academic Free License version 2.0
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   /* Since we have BaseInfo now these could be one list */
47   GSList *methods;
48   GSList *signals;
49 };
50
51 struct MethodInfo
52 {
53   BaseInfo base;
54   GSList *args;
55 };
56
57 struct SignalInfo
58 {
59   BaseInfo base;
60   GSList *args;
61 };
62
63 struct ArgInfo
64 {
65   BaseInfo base;
66   int type;
67   ArgDirection direction;
68 };
69
70 BaseInfo *
71 base_info_ref (BaseInfo *info)
72 {
73   g_return_val_if_fail (info != NULL, NULL);
74   g_return_val_if_fail (info->refcount > 0, NULL);
75   
76   info->refcount += 1;
77
78   return info;
79 }
80
81 static void
82 base_info_free (void *ptr)
83 {
84   BaseInfo *info;
85
86   info = ptr;
87   
88   g_free (info->name);
89   g_free (info);
90 }
91
92 void
93 base_info_unref (BaseInfo *info)
94 {
95   g_return_if_fail (info != NULL);
96   g_return_if_fail (info->refcount > 0);
97   
98   /* This is sort of bizarre, BaseInfo was tacked on later */
99
100   switch (info->type)
101     {
102     case INFO_TYPE_NODE:
103       node_info_unref ((NodeInfo*) info);
104       break;
105     case INFO_TYPE_INTERFACE:
106       interface_info_unref ((InterfaceInfo*) info);
107       break;
108     case INFO_TYPE_SIGNAL:
109       signal_info_unref ((SignalInfo*) info);
110       break;
111     case INFO_TYPE_METHOD:
112       method_info_unref ((MethodInfo*) info);
113       break;
114     case INFO_TYPE_ARG:
115       arg_info_unref ((ArgInfo*) info);
116       break;
117     }
118 }
119
120 InfoType
121 base_info_get_type (BaseInfo      *info)
122 {
123   return info->type;
124 }
125
126 const char*
127 base_info_get_name (BaseInfo *info)
128 {
129   return info->name;
130 }
131
132 void
133 base_info_set_name (BaseInfo      *info,
134                     const char    *name)
135 {
136   char *old;
137
138   old = info->name;
139   info->name = g_strdup (name);
140   g_free (old);
141 }
142
143 GType
144 base_info_get_gtype (void)
145 {
146   static GType our_type = 0;
147   
148   if (our_type == 0)
149     our_type = g_boxed_type_register_static ("BaseInfo",
150                                              (GBoxedCopyFunc) base_info_ref,
151                                              (GBoxedFreeFunc) base_info_unref);
152
153   return our_type;
154 }
155
156 static void
157 free_interface_list (GSList **interfaces_p)
158 {
159   GSList *tmp;
160   tmp = *interfaces_p;
161   while (tmp != NULL)
162     {
163       interface_info_unref (tmp->data);
164       tmp = tmp->next;
165     }
166   g_slist_free (*interfaces_p);
167   *interfaces_p = NULL;
168 }
169
170 static void
171 free_node_list (GSList **nodes_p)
172 {
173   GSList *tmp;
174   tmp = *nodes_p;
175   while (tmp != NULL)
176     {
177       node_info_unref (tmp->data);
178       tmp = tmp->next;
179     }
180   g_slist_free (*nodes_p);
181   *nodes_p = NULL;
182 }
183
184 static void
185 free_method_list (GSList **methods_p)
186 {
187   GSList *tmp;
188   tmp = *methods_p;
189   while (tmp != NULL)
190     {
191       method_info_unref (tmp->data);
192       tmp = tmp->next;
193     }
194   g_slist_free (*methods_p);
195   *methods_p = NULL;
196 }
197
198 static void
199 free_signal_list (GSList **signals_p)
200 {
201   GSList *tmp;
202   tmp = *signals_p;
203   while (tmp != NULL)
204     {
205       signal_info_unref (tmp->data);
206       tmp = tmp->next;
207     }
208   g_slist_free (*signals_p);
209   *signals_p = NULL;
210 }
211
212 NodeInfo*
213 node_info_new (const char *name)
214 {
215   NodeInfo *info;
216
217   /* name can be NULL */
218   
219   info = g_new0 (NodeInfo, 1);
220   info->base.refcount = 1;
221   info->base.name = g_strdup (name);
222   info->base.type = INFO_TYPE_NODE;
223   
224   return info;
225 }
226
227 NodeInfo *
228 node_info_ref (NodeInfo *info)
229 {
230   info->base.refcount += 1;
231
232   return info;
233 }
234
235 void
236 node_info_unref (NodeInfo *info)
237 {
238   info->base.refcount -= 1;
239   if (info->base.refcount == 0)
240     {
241       free_interface_list (&info->interfaces);
242       free_node_list (&info->nodes);
243       base_info_free (info);
244     }
245 }
246
247 const char*
248 node_info_get_name (NodeInfo *info)
249 {
250   return info->base.name;
251 }
252
253 GSList*
254 node_info_get_interfaces (NodeInfo *info)
255 {
256   return info->interfaces;
257 }
258
259 void
260 node_info_add_interface (NodeInfo *info,
261                          InterfaceInfo    *interface)
262 {
263   interface_info_ref (interface);
264   info->interfaces = g_slist_append (info->interfaces, interface);
265 }
266
267 GSList*
268 node_info_get_nodes (NodeInfo *info)
269 {
270   return info->nodes;
271 }
272
273 void
274 node_info_add_node (NodeInfo *info,
275                     NodeInfo *node)
276 {
277   node_info_ref (node);
278   info->nodes = g_slist_append (info->nodes, node);
279 }
280
281 InterfaceInfo*
282 interface_info_new (const char *name)
283 {
284   InterfaceInfo *info;
285
286   info = g_new0 (InterfaceInfo, 1);
287   info->base.refcount = 1;
288   info->base.name = g_strdup (name);
289   info->base.type = INFO_TYPE_INTERFACE;
290   
291   return info;
292 }
293
294 InterfaceInfo *
295 interface_info_ref (InterfaceInfo *info)
296 {
297   info->base.refcount += 1;
298
299   return info;
300 }
301
302 void
303 interface_info_unref (InterfaceInfo *info)
304 {
305   info->base.refcount -= 1;
306   if (info->base.refcount == 0)
307     {
308       free_method_list (&info->methods);
309       free_signal_list (&info->signals);
310       base_info_free (info);
311     }
312 }
313
314 const char*
315 interface_info_get_name (InterfaceInfo *info)
316 {
317   return info->base.name;
318 }
319
320 GSList*
321 interface_info_get_methods (InterfaceInfo *info)
322 {
323   return info->methods;
324 }
325
326 GSList*
327 interface_info_get_signals (InterfaceInfo *info)
328 {
329   return info->signals;
330 }
331
332 void
333 interface_info_add_method (InterfaceInfo *info,
334                            MethodInfo    *method)
335 {
336   method_info_ref (method);
337   info->methods = g_slist_append (info->methods, method);
338 }
339
340 void
341 interface_info_add_signal (InterfaceInfo *info,
342                            SignalInfo    *signal)
343 {
344   signal_info_ref (signal);
345   info->signals = g_slist_append (info->signals, signal);
346 }
347
348 static void
349 free_arg_list (GSList **args_p)
350 {
351   GSList *tmp;
352   tmp = *args_p;
353   while (tmp != NULL)
354     {
355       arg_info_unref (tmp->data);
356       tmp = tmp->next;
357     }
358   g_slist_free (*args_p);
359   *args_p = NULL;
360 }
361
362 MethodInfo*
363 method_info_new (const char *name)
364 {
365   MethodInfo *info;
366
367   info = g_new0 (MethodInfo, 1);
368   info->base.refcount = 1;
369   info->base.name = g_strdup (name);
370   info->base.type = INFO_TYPE_METHOD;
371   
372   return info;
373 }
374
375 MethodInfo *
376 method_info_ref (MethodInfo *info)
377 {
378   info->base.refcount += 1;
379
380   return info;
381 }
382
383 void
384 method_info_unref (MethodInfo *info)
385 {
386   info->base.refcount -= 1;
387   if (info->base.refcount == 0)
388     {
389       free_arg_list (&info->args);
390       base_info_free (info);
391     }
392 }
393
394 const char*
395 method_info_get_name (MethodInfo *info)
396 {
397   return info->base.name;
398 }
399
400 GSList*
401 method_info_get_args (MethodInfo *info)
402 {
403   return info->args;
404 }
405
406 static int
407 args_sort_by_direction (const void *a,
408                         const void *b)
409 {
410   const ArgInfo *arg_a = a;
411   const ArgInfo *arg_b = b;
412
413   if (arg_a->direction == arg_b->direction)
414     return 0;
415   else if (arg_a->direction == ARG_IN)
416     return -1; /* in is less than out */
417   else
418     return 1;
419 }                  
420
421 void
422 method_info_add_arg (MethodInfo    *info,
423                      ArgInfo       *arg)
424 {
425   arg_info_ref (arg);
426   info->args = g_slist_append (info->args, arg);
427
428   /* Keep "in" args sorted before "out" and otherwise maintain
429    * stable order (g_slist_sort is stable, at least in sufficiently
430    * new glib)
431    */
432   info->args = g_slist_sort (info->args, args_sort_by_direction);
433 }
434
435 SignalInfo*
436 signal_info_new (const char *name)
437 {
438   SignalInfo *info;
439
440   info = g_new0 (SignalInfo, 1);
441   info->base.refcount = 1;
442   info->base.name = g_strdup (name);
443   info->base.type = INFO_TYPE_SIGNAL;
444   
445   return info;
446 }
447
448 SignalInfo *
449 signal_info_ref (SignalInfo *info)
450 {
451   info->base.refcount += 1;
452
453   return info;
454 }
455
456 void
457 signal_info_unref (SignalInfo *info)
458 {
459   info->base.refcount -= 1;
460   if (info->base.refcount == 0)
461     {
462       free_arg_list (&info->args);
463       base_info_free (info);
464     }
465 }
466
467 const char*
468 signal_info_get_name (SignalInfo *info)
469 {
470   return info->base.name;
471 }
472
473 GSList*
474 signal_info_get_args (SignalInfo *info)
475 {
476   return info->args;
477 }
478
479 void
480 signal_info_add_arg (SignalInfo    *info,
481                      ArgInfo       *arg)
482 {
483   g_assert (arg->direction == ARG_OUT);
484   
485   arg_info_ref (arg);
486   info->args = g_slist_append (info->args, arg);
487
488   /* signal args don't need sorting since only "out" is allowed */
489 }
490
491 ArgInfo*
492 arg_info_new (const char  *name,
493               ArgDirection direction,
494               int          type)
495 {
496   ArgInfo *info;
497
498   info = g_new0 (ArgInfo, 1);
499   info->base.refcount = 1;
500   info->base.type = INFO_TYPE_ARG;
501   
502   /* name can be NULL */
503   info->base.name = g_strdup (name);
504   info->direction = direction;
505   info->type = type;
506
507   return info;
508 }
509
510 ArgInfo *
511 arg_info_ref (ArgInfo *info)
512 {
513   info->base.refcount += 1;
514
515   return info;
516 }
517
518 void
519 arg_info_unref (ArgInfo *info)
520 {
521   info->base.refcount -= 1;
522   if (info->base.refcount == 0)
523     {
524       base_info_free (info);
525     }
526 }
527 const char*
528 arg_info_get_name (ArgInfo *info)
529 {
530   return info->base.name;
531 }
532
533 int
534 arg_info_get_type (ArgInfo *info)
535 {
536   return info->type;
537 }
538
539 ArgDirection
540 arg_info_get_direction (ArgInfo *info)
541 {
542   return info->direction;
543 }
544
545 #ifdef DBUS_BUILD_TESTS
546
547 /**
548  * @ingroup DBusGIDL
549  * Unit test for GLib IDL internals
550  * @returns #TRUE on success.
551  */
552 dbus_bool_t
553 _dbus_gidl_test (void)
554 {
555
556   return TRUE;
557 }
558
559 #endif /* DBUS_BUILD_TESTS */
560
561 #endif /* DOXYGEN_SHOULD_SKIP_THIS */