source: trunk/third/gtk/gtk/gtkarg.c @ 14482

Revision 14482, 16.9 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r14481, which included commits to RCS files with non-trunk default branches.
Line 
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 --- */
37typedef struct _GtkArgQueryData GtkArgQueryData;
38
39
40/* --- structures --- */
41struct _GtkArgQueryData
42{
43  GList *arg_list;
44  GtkType class_type;
45};
46
47
48
49/* --- functions --- */
50GtkArgInfo*
51gtk_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
117gchar*
118gtk_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
146gchar*
147gtk_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
241gchar*
242gtk_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
295void
296gtk_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
308static void
309gtk_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
325GtkArg*
326gtk_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
391GtkArg*
392gtk_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
403GtkArg*
404gtk_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
424void
425gtk_arg_free (GtkArg  *arg,
426              gboolean free_contents)
427{
428  g_return_if_fail (arg != NULL);
429
430  if (free_contents)
431    gtk_arg_reset (arg);
432  g_free (arg);
433}
434
435void
436gtk_arg_reset (GtkArg *arg)
437{
438  GtkType fundamental_type;
439
440  g_return_if_fail (arg != NULL);
441
442  fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
443  if (fundamental_type > GTK_TYPE_FUNDAMENTAL_LAST)
444    {
445      fundamental_type = gtk_type_get_varargs_type (fundamental_type);
446      if (!fundamental_type)
447        fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
448    }
449
450  if (fundamental_type == GTK_TYPE_STRING)
451    {
452      g_free (GTK_VALUE_STRING (*arg));
453      arg->type = GTK_TYPE_INVALID;
454    }
455  else if (arg->type != GTK_TYPE_INVALID)
456    arg->type = GTK_TYPE_INVALID;
457}
458
459gint
460gtk_arg_info_equal (gconstpointer arg_info_1,
461                    gconstpointer arg_info_2)
462{
463  register const GtkArgInfo *info1 = arg_info_1;
464  register const GtkArgInfo *info2 = arg_info_2;
465 
466  return ((info1->class_type == info2->class_type) &&
467          strcmp (info1->name, info2->name) == 0);
468}
469
470guint
471gtk_arg_info_hash (gconstpointer arg_info)
472{
473  register const GtkArgInfo *info = arg_info;
474  register const gchar *p;
475  register guint h = info->class_type >> 8;
476 
477  for (p = info->name; *p; p++)
478    {
479      register guint g;
480     
481      h = (h << 4) + *p;
482      g = h & 0xf0000000;
483      if (g)
484        {
485          h = h ^ (g >> 24);
486          h = h ^ g;
487        }
488    }
489 
490  return h;
491}
492
493gboolean
494gtk_arg_values_equal (const GtkArg *arg1,
495                      const GtkArg *arg2)
496{
497  GtkType fundamental_type;
498  gboolean equal;
499 
500  g_return_val_if_fail (arg1 != NULL, FALSE);
501  g_return_val_if_fail (arg2 != NULL, FALSE);
502  g_return_val_if_fail (GTK_FUNDAMENTAL_TYPE (arg1->type) ==
503                        GTK_FUNDAMENTAL_TYPE (arg2->type), FALSE);
504 
505  fundamental_type = GTK_FUNDAMENTAL_TYPE (arg1->type);
506  if (fundamental_type > GTK_TYPE_FUNDAMENTAL_LAST)
507    {
508      fundamental_type = gtk_type_get_varargs_type (fundamental_type);
509      if (!fundamental_type)
510        fundamental_type = GTK_FUNDAMENTAL_TYPE (arg1->type);
511    }
512 
513  switch (fundamental_type)
514    {
515    case GTK_TYPE_INVALID:
516      equal = TRUE;
517      break;
518    case GTK_TYPE_CHAR:
519      equal = GTK_VALUE_CHAR (*arg1) == GTK_VALUE_CHAR (*arg2);
520      break;
521    case GTK_TYPE_BOOL:
522      equal = (GTK_VALUE_BOOL (*arg1) != FALSE) == (GTK_VALUE_BOOL (*arg2) != FALSE);
523      break;
524    case GTK_TYPE_INT:
525      equal = GTK_VALUE_INT (*arg1) == GTK_VALUE_INT (*arg2);
526      break;
527    case GTK_TYPE_UINT:
528      equal = GTK_VALUE_UINT (*arg1) == GTK_VALUE_UINT (*arg2);
529      break;
530    case GTK_TYPE_LONG:
531      equal = GTK_VALUE_LONG (*arg1) == GTK_VALUE_LONG (*arg2);
532      break;
533    case GTK_TYPE_ULONG:
534      equal = GTK_VALUE_ULONG (*arg1) == GTK_VALUE_ULONG (*arg2);
535      break;
536    case GTK_TYPE_FLOAT:
537      equal = GTK_VALUE_FLOAT (*arg1) == GTK_VALUE_FLOAT (*arg2);
538      break;
539    case GTK_TYPE_DOUBLE:
540      equal = GTK_VALUE_DOUBLE (*arg1) == GTK_VALUE_DOUBLE (*arg2);
541      break;
542    case GTK_TYPE_STRING:
543      if (!GTK_VALUE_STRING (*arg1) ||
544          !GTK_VALUE_STRING (*arg2))
545        equal = GTK_VALUE_STRING (*arg1) == GTK_VALUE_STRING (*arg2);
546      else
547        equal = g_str_equal (GTK_VALUE_STRING (*arg1), GTK_VALUE_STRING (*arg2));
548      break;
549    case GTK_TYPE_ENUM:
550      equal = GTK_VALUE_ENUM (*arg1) == GTK_VALUE_ENUM (*arg2);
551      break;
552    case GTK_TYPE_FLAGS:
553      equal = GTK_VALUE_FLAGS (*arg1) == GTK_VALUE_FLAGS (*arg2);
554      break;
555    case GTK_TYPE_BOXED:
556      equal = GTK_VALUE_BOXED (*arg1) == GTK_VALUE_BOXED (*arg2);
557      break;
558    case GTK_TYPE_FOREIGN:
559      equal = (GTK_VALUE_FOREIGN (*arg1).data == GTK_VALUE_FOREIGN (*arg2).data &&
560               GTK_VALUE_FOREIGN (*arg1).notify == GTK_VALUE_FOREIGN (*arg2).notify);
561      break;
562    case GTK_TYPE_CALLBACK:
563      equal = (GTK_VALUE_CALLBACK (*arg1).marshal == GTK_VALUE_CALLBACK (*arg2).marshal &&
564               GTK_VALUE_CALLBACK (*arg1).data == GTK_VALUE_CALLBACK (*arg2).data &&
565               GTK_VALUE_CALLBACK (*arg1).notify == GTK_VALUE_CALLBACK (*arg2).notify);
566      break;
567    case GTK_TYPE_ARGS:
568      equal = (GTK_VALUE_ARGS (*arg1).n_args == GTK_VALUE_ARGS (*arg2).n_args &&
569               GTK_VALUE_ARGS (*arg1).args == GTK_VALUE_ARGS (*arg2).args);
570      break;
571    case GTK_TYPE_OBJECT:
572      equal = GTK_VALUE_OBJECT (*arg1) == GTK_VALUE_OBJECT (*arg2);
573      break;
574    case GTK_TYPE_POINTER:
575      equal = GTK_VALUE_POINTER (*arg1) == GTK_VALUE_POINTER (*arg2);
576      break;
577    case GTK_TYPE_SIGNAL:
578      equal = (GTK_VALUE_SIGNAL (*arg1).f == GTK_VALUE_SIGNAL (*arg2).f &&
579               GTK_VALUE_SIGNAL (*arg1).d == GTK_VALUE_SIGNAL (*arg2).d);
580      break;
581    case GTK_TYPE_C_CALLBACK:
582      equal = (GTK_VALUE_C_CALLBACK (*arg1).func == GTK_VALUE_C_CALLBACK (*arg2).func &&
583               GTK_VALUE_C_CALLBACK (*arg1).func_data == GTK_VALUE_C_CALLBACK (*arg2).func_data);
584      break;
585    default:
586      g_warning ("gtk_arg_values_equal() used with unknown type `%s'", gtk_type_name (arg1->type));
587      equal = FALSE;
588      break;
589    }
590 
591  return equal;
592}
593
594void
595gtk_arg_to_valueloc (GtkArg  *arg,
596                     gpointer value_pointer)
597{
598  GtkType fundamental_type;
599 
600  g_return_if_fail (arg != NULL);
601  g_return_if_fail (value_pointer != NULL);
602 
603  fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
604  if (fundamental_type > GTK_TYPE_FUNDAMENTAL_LAST)
605    {
606      fundamental_type = gtk_type_get_varargs_type (fundamental_type);
607      if (!fundamental_type)
608        fundamental_type = GTK_FUNDAMENTAL_TYPE (arg->type);
609    }
610 
611  switch (fundamental_type)
612    {
613      gchar *p_char;
614      guchar *p_uchar;
615      gboolean *p_boolean;
616      gint *p_int;
617      guint *p_uint;
618      glong *p_long;
619      gulong *p_ulong;
620      gfloat *p_float;
621      gdouble *p_double;
622      gpointer *p_pointer;
623    case GTK_TYPE_CHAR:
624      p_char = value_pointer;
625      *p_char = GTK_VALUE_CHAR (*arg);
626      break;
627    case GTK_TYPE_UCHAR:
628      p_uchar = value_pointer;
629      *p_uchar = GTK_VALUE_UCHAR (*arg);
630      break;
631    case GTK_TYPE_BOOL:
632      p_boolean = value_pointer;
633      *p_boolean = GTK_VALUE_BOOL (*arg);
634      break;
635    case GTK_TYPE_INT:
636    case GTK_TYPE_ENUM:
637      p_int = value_pointer;
638      *p_int = GTK_VALUE_INT (*arg);
639      break;
640    case GTK_TYPE_UINT:
641    case GTK_TYPE_FLAGS:
642      p_uint = value_pointer;
643      *p_uint = GTK_VALUE_UINT (*arg);
644      break;
645    case GTK_TYPE_LONG:
646      p_long = value_pointer;
647      *p_long = GTK_VALUE_LONG (*arg);
648      break;
649    case GTK_TYPE_ULONG:
650      p_ulong = value_pointer;
651      *p_ulong = GTK_VALUE_ULONG (*arg);
652      break;
653    case GTK_TYPE_FLOAT:
654      p_float = value_pointer;
655      *p_float = GTK_VALUE_FLOAT (*arg);
656      break;
657    case GTK_TYPE_DOUBLE:
658      p_double = value_pointer;
659      *p_double = GTK_VALUE_DOUBLE (*arg);
660      break;
661    case GTK_TYPE_STRING:
662    case GTK_TYPE_POINTER:
663    case GTK_TYPE_BOXED:
664    case GTK_TYPE_OBJECT:
665      p_pointer = value_pointer;
666      *p_pointer = GTK_VALUE_POINTER (*arg);
667      break;
668    case GTK_TYPE_SIGNAL:
669    case GTK_TYPE_ARGS:
670    case GTK_TYPE_FOREIGN:
671    case GTK_TYPE_CALLBACK:
672    case GTK_TYPE_C_CALLBACK:
673    case GTK_TYPE_NONE:
674    case GTK_TYPE_INVALID:
675      /* it doesn't make much sense to retrive these values,
676       * they either are always read-only args, or require
677       * multiple pointers.
678       */
679      g_warning ("gtk_arg_fill_retloc(): unsupported argument type `%s'",
680                 gtk_type_name (arg->type));
681      break;
682    }
683}
Note: See TracBrowser for help on using the repository browser.