]> Pileus Git - ~andy/gtk/blob - gtk/gtkarg.c
ff543e63ca1d6e656b52ef391e46f85dd809ca57
[~andy/gtk] / gtk / gtkarg.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <stdarg.h>
20 #include <string.h>
21 #include "gtkobject.h"
22 #include "gtkargcollector.c"
23
24
25 #define MAX_ARG_LENGTH  (256)
26
27
28 /* --- typedefs --- */
29 typedef struct _GtkArgQueryData GtkArgQueryData;
30
31
32 /* --- structures --- */
33 struct _GtkArgQueryData
34 {
35   GList *arg_list;
36   GtkType class_type;
37 };
38
39
40
41 /* --- functions --- */
42 GtkArgInfo*
43 gtk_arg_type_new_static (GtkType      base_class_type,
44                          const gchar *arg_name,
45                          guint        class_n_args_offset,
46                          GHashTable  *arg_info_hash_table,
47                          GtkType      arg_type,
48                          guint        arg_flags,
49                          guint        arg_id)
50 {
51   GtkArgInfo *info;
52   gchar class_part[MAX_ARG_LENGTH];
53   gchar *arg_part;
54   GtkType class_type;
55   guint class_offset;
56   guint *n_args_p;
57   gchar *p;
58
59   g_return_val_if_fail (arg_name != NULL, NULL);
60   g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (base_class_type) == GTK_TYPE_OBJECT, NULL);
61   g_return_val_if_fail (class_n_args_offset != 0, NULL);
62   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
63   g_return_val_if_fail (arg_type > GTK_TYPE_NONE, NULL);
64   g_return_val_if_fail (arg_id > 0, NULL);
65   g_return_val_if_fail ((arg_flags & GTK_ARG_READWRITE) != 0, NULL);
66   /* g_return_val_if_fail ((arg_flags & GTK_ARG_CHILD_ARG) == 0, NULL); */
67   
68   arg_flags &= GTK_ARG_MASK;
69
70   arg_part = strchr (arg_name, ':');
71   if (!arg_part || (arg_part[0] != ':') || (arg_part[1] != ':'))
72     {
73       g_warning ("gtk_arg_type_new(): invalid arg name: \"%s\"\n", arg_name);
74       return NULL;
75     }
76
77   class_offset = (guint) (arg_part - arg_name);
78   strncpy (class_part, arg_name, class_offset);
79   class_part[class_offset] = 0;
80
81   class_type = gtk_type_from_name (class_part);
82   if (!gtk_type_is_a (class_type, base_class_type))
83     {
84       g_warning ("gtk_arg_type_new(): argument class in \"%s\" is not in the `%s' ancestry",
85                  arg_name,
86                  gtk_type_name (base_class_type));
87       return NULL;
88     }
89
90   p = gtk_type_class (class_type);
91   p += class_n_args_offset;
92   n_args_p = (guint*) p;
93   *n_args_p += 1;
94
95   info = g_new (GtkArgInfo, 1);
96   info->class_type = class_type;
97   info->full_name = (gchar*) arg_name; /* _static */
98   info->name = info->full_name + class_offset + 2;
99   info->type = arg_type;
100   info->arg_flags = arg_flags;
101   info->arg_id = arg_id;
102   info->seq_id = *n_args_p;
103
104   g_hash_table_insert (arg_info_hash_table, info, info);
105
106   return info;
107 }
108
109 gchar*
110 gtk_arg_name_strip_type (const gchar   *arg_name)
111 {
112   gchar buffer[MAX_ARG_LENGTH];
113   gchar *p;
114
115   /* security audit
116    */
117   if (!arg_name || strlen (arg_name) > MAX_ARG_LENGTH - 8)
118     return NULL;
119
120   p = strchr (arg_name, ':');
121   if (p)
122     {
123       guint len;
124
125       if ((p[0] != ':') || (p[1] != ':') || (p[2] == 0))
126         return NULL;
127       len = (guint) (p - arg_name);
128       strncpy (buffer, arg_name, len);
129       buffer[len] = 0;
130
131       if (gtk_type_from_name (buffer) != GTK_TYPE_INVALID)
132         return p + 2;
133     }
134
135   return (gchar*) arg_name;
136 }
137
138 gchar*
139 gtk_arg_get_info (GtkType       object_type,
140                   GHashTable   *arg_info_hash_table,
141                   const gchar  *arg_name,
142                   GtkArgInfo  **info_p)
143 {
144   GtkType otype;
145   gchar buffer[MAX_ARG_LENGTH];
146   guint len;
147   gchar *p;
148   
149   *info_p = NULL;
150   
151   /* security audit
152    */
153   if (!arg_name || strlen (arg_name) > MAX_ARG_LENGTH - 8)
154     return g_strdup ("argument name exceeds maximum size.");
155
156   /* split off the object-type part
157    */
158   p = strchr (arg_name, ':');
159   if (p)
160     {
161       if ((p[0] != ':') || (p[1] != ':'))
162         return g_strconcat ("invalid argument syntax: \"",
163                             arg_name,
164                             "\"",
165                             NULL);
166       len = (guint) (p - arg_name);
167       strncpy (buffer, arg_name, len);
168       buffer[len] = 0;
169
170       otype = gtk_type_from_name (buffer);
171       if (otype != GTK_TYPE_INVALID)
172         arg_name = p + 2;
173     }
174   else
175     otype = GTK_TYPE_INVALID;
176
177   /* split off the argument name
178    */
179   p = strchr (arg_name, ':');
180   if (p)
181     {
182       if ((p[0] != ':') || (p[1] != ':'))
183         return g_strconcat ("invalid argument syntax: \"",
184                             arg_name,
185                             "\"",
186                             NULL);
187       len = (guint) (p - arg_name);
188       strncpy (buffer, arg_name, len);
189       buffer[len] = 0;
190       arg_name = buffer;
191     }
192
193   /* lookup the argument
194    */
195   if (otype != GTK_TYPE_INVALID)
196     {
197       GtkArgInfo info;
198
199       info.class_type = otype;
200       info.name = (gchar*) arg_name;
201
202       *info_p = g_hash_table_lookup (arg_info_hash_table, &info);
203       if (*info_p && !gtk_type_is_a (object_type, (*info_p)->class_type))
204         *info_p = NULL;
205     }
206   else
207     {
208       otype = object_type;
209       while (!*info_p && GTK_FUNDAMENTAL_TYPE (otype) == GTK_TYPE_OBJECT)
210         {
211           GtkArgInfo info;
212           
213           info.class_type = otype;
214           info.name = (gchar*) arg_name;
215           
216           *info_p = g_hash_table_lookup (arg_info_hash_table, &info);
217           
218           otype = gtk_type_parent (otype);
219         }
220     }
221   
222   if (!*info_p)
223     return g_strconcat ("could not find argument \"",
224                         arg_name,
225                         "\" in the `",
226                         gtk_type_name (object_type),
227                         "' class ancestry",
228                         NULL);
229
230   return NULL;
231 }
232
233 gchar*
234 gtk_args_collect (GtkType         object_type,
235                   GHashTable     *arg_info_hash_table,
236                   GSList        **arg_list_p,
237                   GSList        **info_list_p,
238                   const gchar   *first_arg_name,
239                   va_list        var_args)
240 {
241   GSList *arg_list;
242   GSList *info_list;
243   const gchar *arg_name;
244
245   g_return_val_if_fail (arg_list_p != NULL, NULL);
246   *arg_list_p = NULL;
247   g_return_val_if_fail (info_list_p != NULL, NULL);
248   *info_list_p = 0;
249   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
250
251   arg_list = NULL;
252   info_list = NULL;
253   arg_name = first_arg_name;
254   while (arg_name)
255     {
256       GtkArgInfo *info = NULL;
257       gchar *error;
258
259       error = gtk_arg_get_info (object_type, arg_info_hash_table, arg_name, &info);
260       if (!error)
261         {
262           GtkArg *arg;
263
264           info_list = g_slist_prepend (info_list, info);
265
266           arg = gtk_arg_new (info->type);
267           arg->name = (gchar*) arg_name;
268           GTK_ARG_COLLECT_VALUE (arg, var_args, error);
269           arg_list = g_slist_prepend (arg_list, arg);
270         }
271       if (error)
272         {
273           gtk_args_collect_cleanup (arg_list, info_list);
274
275           return error;
276         }
277
278       arg_name = va_arg (var_args, gchar*);
279     }
280
281   *arg_list_p = g_slist_reverse (arg_list);
282   *info_list_p = g_slist_reverse (info_list);
283
284   return NULL;
285 }
286
287 void
288 gtk_args_collect_cleanup (GSList        *arg_list,
289                           GSList        *info_list)
290 {
291   GSList *slist;
292   
293   g_slist_free (info_list);
294
295   for (slist = arg_list; slist; slist = slist->next)
296     gtk_arg_free (slist->data, FALSE);
297   g_slist_free (arg_list);
298 }
299
300 static void
301 gtk_args_query_foreach (gpointer key,
302                         gpointer value,
303                         gpointer user_data)
304 {
305   register GtkArgInfo *info;
306   register GtkArgQueryData *data;
307
308   g_assert (key == value); /* paranoid */
309
310   info = value;
311   data = user_data;
312
313   if (info->class_type == data->class_type)
314     data->arg_list = g_list_prepend (data->arg_list, info);
315 }
316
317 GtkArg*
318 gtk_args_query (GtkType     class_type,
319                 GHashTable *arg_info_hash_table,
320                 guint32   **arg_flags,
321                 guint      *n_args_p)
322 {
323   GtkArg *args;
324   GtkArgQueryData query_data;
325
326   if (arg_flags)
327     *arg_flags = NULL;
328   g_return_val_if_fail (n_args_p != NULL, NULL);
329   *n_args_p = 0;
330   g_return_val_if_fail (arg_info_hash_table != NULL, NULL);
331
332   /* make sure the types class has been initialized, because
333    * the argument setup happens in the gtk_*_class_init() functions.
334    */
335   gtk_type_class (class_type);
336
337   query_data.arg_list = NULL;
338   query_data.class_type = class_type;
339   g_hash_table_foreach (arg_info_hash_table, gtk_args_query_foreach, &query_data);
340
341   if (query_data.arg_list)
342     {
343       register GList    *list;
344       register guint    len;
345
346       list = query_data.arg_list;
347       len = 1;
348       while (list->next)
349         {
350           len++;
351           list = list->next;
352         }
353
354       args = g_new0 (GtkArg, len);
355       *n_args_p = len;
356       if (arg_flags)
357         *arg_flags = g_new (guint32, len);
358
359       do
360         {
361           GtkArgInfo *info;
362
363           info = list->data;
364           list = list->prev;
365
366           g_assert (info->seq_id > 0 && info->seq_id <= len); /* paranoid */
367
368           args[info->seq_id - 1].type = info->type;
369           args[info->seq_id - 1].name = info->full_name;
370           if (arg_flags)
371             (*arg_flags)[info->seq_id - 1] = info->arg_flags;
372         }
373       while (list);
374
375       g_list_free (query_data.arg_list);
376     }
377   else
378     args = NULL;
379
380   return args;
381 }
382
383 GtkArg*
384 gtk_arg_new (GtkType  arg_type)
385 {
386   GtkArg *arg;
387
388   arg = g_new0 (GtkArg, 1);
389   arg->type = arg_type;
390   arg->name = NULL;
391
392   return arg;
393 }
394
395 GtkArg*
396 gtk_arg_copy (GtkArg         *src_arg,
397               GtkArg         *dest_arg)
398 {
399   g_return_val_if_fail (src_arg != NULL, NULL);
400
401   if (!dest_arg)
402     {
403       dest_arg = g_new0 (GtkArg, 1);
404       dest_arg->name = src_arg->name;
405     }
406
407   dest_arg->type = src_arg->type;
408   dest_arg->d = src_arg->d;
409
410   if (src_arg->type == GTK_TYPE_STRING)
411     GTK_VALUE_STRING (*dest_arg) = g_strdup (GTK_VALUE_STRING (*src_arg));
412
413   return dest_arg;
414 }
415
416 void
417 gtk_arg_free (GtkArg        *arg,
418               gboolean       free_contents)
419 {
420   g_return_if_fail (arg != NULL);
421
422   if (free_contents &&
423       GTK_FUNDAMENTAL_TYPE (arg->type) == GTK_TYPE_STRING)
424     g_free (GTK_VALUE_STRING (*arg));
425   g_free (arg);
426 }
427
428 gint
429 gtk_arg_info_equal (gconstpointer arg_info_1,
430                     gconstpointer arg_info_2)
431 {
432   register const GtkArgInfo *info1 = arg_info_1;
433   register const GtkArgInfo *info2 = arg_info_2;
434   
435   return ((info1->class_type == info2->class_type) &&
436           strcmp (info1->name, info2->name) == 0);
437 }
438
439 guint
440 gtk_arg_info_hash (gconstpointer arg_info)
441 {
442   register const GtkArgInfo *info = arg_info;
443   register const gchar *p;
444   register guint h = info->class_type >> 8;
445   
446   for (p = info->name; *p; p++)
447     {
448       register guint g;
449       
450       h = (h << 4) + *p;
451       g = h & 0xf0000000;
452       if (g)
453         {
454           h = h ^ (g >> 24);
455           h = h ^ g;
456         }
457     }
458   
459   return h;
460 }