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