00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "dbus-gtype-specialized.h"
00026 #include <glib.h>
00027 #include <string.h>
00028 #include <gobject/gvaluecollector.h>
00029
00060 typedef enum {
00061 DBUS_G_SPECTYPE_COLLECTION,
00062 DBUS_G_SPECTYPE_MAP,
00063 DBUS_G_SPECTYPE_STRUCT
00064 } DBusGTypeSpecializedType;
00065
00066 typedef struct {
00067 DBusGTypeSpecializedType type;
00068 const DBusGTypeSpecializedVtable *vtable;
00069 } DBusGTypeSpecializedContainer;
00070
00071 typedef struct {
00072 guint num_types;
00073 GType *types;
00074 const DBusGTypeSpecializedContainer *klass;
00075 } DBusGTypeSpecializedData;
00076
00077 static GHashTable *specialized_containers;
00078
00079 static GQuark
00080 specialized_type_data_quark ()
00081 {
00082 static GQuark quark;
00083 if (!quark)
00084 quark = g_quark_from_static_string ("DBusGTypeSpecializedData");
00085
00086 return quark;
00087 }
00088
00089 void
00090 dbus_g_type_specialized_init (void)
00091 {
00092 specialized_containers = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
00093 }
00094
00095 static gboolean
00096 specialized_types_is_initialized (void)
00097 {
00098 return specialized_containers != NULL;
00099 }
00100
00101 static DBusGTypeSpecializedData *
00102 lookup_specialization_data (GType type)
00103 {
00104 return g_type_get_qdata (type, specialized_type_data_quark ());
00105 }
00106
00107
00108
00109 static void
00110 proxy_value_init (GValue *value)
00111 {
00112 value->data[0].v_pointer = NULL;
00113 }
00114
00115
00116 static void
00117 proxy_value_free (GValue *value)
00118 {
00119 if (value->data[0].v_pointer && !(value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS))
00120 {
00121 DBusGTypeSpecializedData *data;
00122 GType type;
00123
00124 type = G_VALUE_TYPE (value);
00125 data = lookup_specialization_data (type);
00126 g_assert (data != NULL);
00127
00128 if (data->klass->vtable->free_func)
00129 {
00130 data->klass->vtable->free_func (type, value->data[0].v_pointer);
00131 }
00132 else
00133 {
00134 g_assert (data->klass->vtable->simple_free_func != NULL);
00135 data->klass->vtable->simple_free_func (value->data[0].v_pointer);
00136 }
00137 }
00138 }
00139
00140
00141 static void
00142 proxy_value_copy (const GValue *src_value,
00143 GValue *dest_value)
00144 {
00145 if (src_value->data[0].v_pointer)
00146 {
00147 DBusGTypeSpecializedData *data;
00148 GType type;
00149 type = G_VALUE_TYPE (src_value);
00150 data = lookup_specialization_data (type);
00151 g_assert (data != NULL);
00152 dest_value->data[0].v_pointer = data->klass->vtable->copy_func (type, src_value->data[0].v_pointer);
00153 }
00154 else
00155 dest_value->data[0].v_pointer = src_value->data[0].v_pointer;
00156 }
00157
00158
00159 static gpointer
00160 proxy_value_peek_pointer (const GValue *value)
00161 {
00162 return value->data[0].v_pointer;
00163 }
00164
00165
00166 static gchar*
00167 proxy_collect_value (GValue *value,
00168 guint n_collect_values,
00169 GTypeCValue *collect_values,
00170 guint collect_flags)
00171 {
00172 DBusGTypeSpecializedData *data;
00173 GType type;
00174
00175 type = G_VALUE_TYPE (value);
00176 data = lookup_specialization_data (type);
00177
00178 if (!collect_values[0].v_pointer)
00179 value->data[0].v_pointer = NULL;
00180 else
00181 {
00182 if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
00183 {
00184 value->data[0].v_pointer = collect_values[0].v_pointer;
00185 value->data[1].v_uint = G_VALUE_NOCOPY_CONTENTS;
00186 }
00187 else
00188 {
00189 value->data[0].v_pointer = data->klass->vtable->copy_func (type, collect_values[0].v_pointer);
00190 }
00191 }
00192
00193 return NULL;
00194 }
00195
00196
00197 static gchar*
00198 proxy_lcopy_value (const GValue *value,
00199 guint n_collect_values,
00200 GTypeCValue *collect_values,
00201 guint collect_flags)
00202 {
00203 gpointer *boxed_p = collect_values[0].v_pointer;
00204
00205 if (!boxed_p)
00206 return g_strdup_printf ("value location for `%s' passed as NULL", G_VALUE_TYPE_NAME (value));
00207
00208 if (!value->data[0].v_pointer)
00209 *boxed_p = NULL;
00210 else if (collect_flags & G_VALUE_NOCOPY_CONTENTS)
00211 *boxed_p = value->data[0].v_pointer;
00212 else
00213 {
00214 DBusGTypeSpecializedData *data;
00215 GType type;
00216
00217 type = G_VALUE_TYPE (value);
00218 data = lookup_specialization_data (type);
00219
00220 *boxed_p = data->klass->vtable->copy_func (type, value->data[0].v_pointer);
00221 }
00222
00223 return NULL;
00224 }
00225
00226 static char *
00227 build_specialization_name (const char *prefix, guint num_types, const GType *types)
00228 {
00229 GString *fullname;
00230 guint i;
00231
00232 fullname = g_string_new (prefix);
00233
00234 g_string_append_c (fullname, '_');
00235 for (i=0; i < num_types; i++)
00236 {
00237 if (i!=0)
00238 g_string_append_c (fullname, '+');
00239 g_string_append (fullname, g_type_name (types[i]));
00240 }
00241 g_string_append_c (fullname, '_');
00242 return g_string_free (fullname, FALSE);
00243 }
00244
00245 static void
00246 register_container (const char *name,
00247 DBusGTypeSpecializedType type,
00248 const DBusGTypeSpecializedVtable *vtable)
00249 {
00250 DBusGTypeSpecializedContainer *klass;
00251
00252 klass = g_new0 (DBusGTypeSpecializedContainer, 1);
00253 klass->type = type;
00254 klass->vtable = vtable;
00255
00256 g_hash_table_insert (specialized_containers, g_strdup (name), klass);
00257 }
00258
00267 void
00268 dbus_g_type_register_collection (const char *name,
00269 const DBusGTypeSpecializedCollectionVtable *vtable,
00270 guint flags)
00271 {
00272 g_return_if_fail (specialized_types_is_initialized ());
00273 register_container (name, DBUS_G_SPECTYPE_COLLECTION, (const DBusGTypeSpecializedVtable*) vtable);
00274 }
00275
00284 void
00285 dbus_g_type_register_map (const char *name,
00286 const DBusGTypeSpecializedMapVtable *vtable,
00287 guint flags)
00288 {
00289 g_return_if_fail (specialized_types_is_initialized ());
00290 register_container (name, DBUS_G_SPECTYPE_MAP, (const DBusGTypeSpecializedVtable*) vtable);
00291 }
00292
00301 void
00302 dbus_g_type_register_struct (const char *name,
00303 const DBusGTypeSpecializedStructVtable *vtable,
00304 guint flags)
00305 {
00306 g_return_if_fail (specialized_types_is_initialized ());
00307 register_container (name, DBUS_G_SPECTYPE_STRUCT, (const DBusGTypeSpecializedVtable*) vtable);
00308 }
00309
00316 const DBusGTypeSpecializedMapVtable* dbus_g_type_map_peek_vtable (GType map_type)
00317 {
00318 DBusGTypeSpecializedData *data;
00319 g_return_val_if_fail (dbus_g_type_is_map(map_type), NULL);
00320
00321 data = lookup_specialization_data (map_type);
00322 g_assert (data != NULL);
00323
00324 return (DBusGTypeSpecializedMapVtable *)(data->klass->vtable);
00325 }
00326
00333 const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (GType collection_type)
00334 {
00335 DBusGTypeSpecializedData *data;
00336 g_return_val_if_fail (dbus_g_type_is_collection(collection_type), NULL);
00337
00338 data = lookup_specialization_data (collection_type);
00339 g_assert (data != NULL);
00340
00341 return (DBusGTypeSpecializedCollectionVtable *)(data->klass->vtable);
00342 }
00343
00350 const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type)
00351 {
00352 DBusGTypeSpecializedData *data;
00353 g_return_val_if_fail (dbus_g_type_is_struct (struct_type), NULL);
00354
00355 data = lookup_specialization_data (struct_type);
00356 g_assert (data != NULL);
00357
00358 return (DBusGTypeSpecializedStructVtable *)(data->klass->vtable);
00359 }
00360
00361 static GType
00362 register_specialized_instance (const DBusGTypeSpecializedContainer *klass,
00363 const char *name,
00364 guint num_types,
00365 const GType *types)
00366 {
00367 GType ret;
00368
00369 static const GTypeValueTable vtable =
00370 {
00371 proxy_value_init,
00372 proxy_value_free,
00373 proxy_value_copy,
00374 proxy_value_peek_pointer,
00375 "p",
00376 proxy_collect_value,
00377 "p",
00378 proxy_lcopy_value,
00379 };
00380 static const GTypeInfo derived_info =
00381 {
00382 0,
00383 NULL,
00384 NULL,
00385 NULL,
00386 NULL,
00387 NULL,
00388 0,
00389 0,
00390 NULL,
00391 &vtable,
00392 };
00393
00394 ret = g_type_register_static (G_TYPE_BOXED, name, &derived_info, 0);
00395
00396 if (ret != G_TYPE_INVALID)
00397 {
00398 DBusGTypeSpecializedData *data;
00399 data = g_new0 (DBusGTypeSpecializedData, 1);
00400 data->num_types = num_types;
00401 data->types = g_memdup (types, sizeof (GType) * num_types);
00402 data->klass = klass;
00403 g_type_set_qdata (ret, specialized_type_data_quark (), data);
00404 }
00405
00406 return ret;
00407 }
00408
00409 static GType
00410 lookup_or_register_specialized (const char *container,
00411 guint num_types,
00412 const GType *types)
00413 {
00414 GType ret;
00415 char *name;
00416 const DBusGTypeSpecializedContainer *klass;
00417
00418 g_return_val_if_fail (specialized_types_is_initialized (), G_TYPE_INVALID);
00419
00420 klass = g_hash_table_lookup (specialized_containers, container);
00421 g_return_val_if_fail (klass != NULL, G_TYPE_INVALID);
00422
00423 name = build_specialization_name (container, num_types, types);
00424 ret = g_type_from_name (name);
00425 if (ret == G_TYPE_INVALID)
00426 {
00427
00428 ret = register_specialized_instance (klass, name,
00429 num_types,
00430 types);
00431 }
00432 g_free (name);
00433 return ret;
00434 }
00435
00436
00447 GType
00448 dbus_g_type_get_collection (const char *container,
00449 GType specialization)
00450 {
00451 return lookup_or_register_specialized (container, 1, &specialization);
00452 }
00453
00465 GType
00466 dbus_g_type_get_map (const char *container,
00467 GType key_specialization,
00468 GType value_specialization)
00469 {
00470 GType types[2];
00471 types[0] = key_specialization;
00472 types[1] = value_specialization;
00473 return lookup_or_register_specialized (container, 2, types);
00474 }
00475
00487 GType
00488 dbus_g_type_get_structv (const char *container,
00489 guint num_members,
00490 GType *types)
00491 {
00492 return lookup_or_register_specialized (container, num_members, types);
00493 }
00494
00506 GType
00507 dbus_g_type_get_struct (const char *container,
00508 GType first_type,
00509 ...)
00510 {
00511 GArray *types;
00512 GType curtype, ret;
00513 va_list args;
00514 va_start (args, first_type);
00515
00516 types = g_array_new (FALSE, FALSE, sizeof (GType));
00517 curtype = first_type;
00518 while (curtype != G_TYPE_INVALID)
00519 {
00520 g_array_append_val (types, curtype);
00521 curtype = va_arg (args, GType);
00522 }
00523 va_end (args);
00524
00525 ret = lookup_or_register_specialized (container, types->len,
00526 (GType *) types->data);
00527
00528 g_array_free (types, TRUE);
00529
00530 return ret;
00531 }
00532
00533
00542 gboolean
00543 dbus_g_type_is_collection (GType gtype)
00544 {
00545 DBusGTypeSpecializedData *data;
00546 data = lookup_specialization_data (gtype);
00547 if (data == NULL)
00548 return FALSE;
00549 return data->klass->type == DBUS_G_SPECTYPE_COLLECTION;
00550 }
00551
00561 gboolean
00562 dbus_g_type_is_map (GType gtype)
00563 {
00564 DBusGTypeSpecializedData *data;
00565 data = lookup_specialization_data (gtype);
00566 if (data == NULL)
00567 return FALSE;
00568 return data->klass->type == DBUS_G_SPECTYPE_MAP;
00569 }
00570
00580 gboolean
00581 dbus_g_type_is_struct (GType gtype)
00582 {
00583 DBusGTypeSpecializedData *data;
00584 data = lookup_specialization_data (gtype);
00585 if (data == NULL)
00586 return FALSE;
00587 return data->klass->type == DBUS_G_SPECTYPE_STRUCT;
00588 }
00589
00590
00591 static GType
00592 get_specialization_index (GType gtype, guint i)
00593 {
00594 DBusGTypeSpecializedData *data;
00595
00596 data = lookup_specialization_data (gtype);
00597 if (i < data->num_types)
00598 return data->types[i];
00599 else
00600 return G_TYPE_INVALID;
00601 }
00602
00610 GType
00611 dbus_g_type_get_collection_specialization (GType gtype)
00612 {
00613 g_return_val_if_fail (dbus_g_type_is_collection (gtype), G_TYPE_INVALID);
00614 return get_specialization_index (gtype, 0);
00615 }
00616
00624 GType
00625 dbus_g_type_get_map_key_specialization (GType gtype)
00626 {
00627 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
00628 return get_specialization_index (gtype, 0);
00629 }
00630
00638 GType
00639 dbus_g_type_get_map_value_specialization (GType gtype)
00640 {
00641 g_return_val_if_fail (dbus_g_type_is_map (gtype), G_TYPE_INVALID);
00642 return get_specialization_index (gtype, 1);
00643 }
00644
00653 GType
00654 dbus_g_type_get_struct_member_type (GType gtype, guint member)
00655 {
00656 g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
00657 return get_specialization_index (gtype, member);
00658 }
00659
00667 guint
00668 dbus_g_type_get_struct_size (GType gtype)
00669 {
00670 DBusGTypeSpecializedData *data;
00671 g_return_val_if_fail (dbus_g_type_is_struct (gtype), G_TYPE_INVALID);
00672
00673 data = lookup_specialization_data (gtype);
00674 return data->num_types;
00675 }
00676
00689 gpointer
00690 dbus_g_type_specialized_construct (GType gtype)
00691 {
00692 DBusGTypeSpecializedData *data;
00693 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00694
00695 data = lookup_specialization_data (gtype);
00696 g_return_val_if_fail (data != NULL, FALSE);
00697
00698 return data->klass->vtable->constructor (gtype);
00699 }
00700
00709 gboolean
00710 dbus_g_type_collection_get_fixed (GValue *value,
00711 gpointer *data_ret,
00712 guint *len_ret)
00713 {
00714 DBusGTypeSpecializedData *data;
00715 GType gtype;
00716
00717 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00718 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
00719
00720 gtype = G_VALUE_TYPE (value);
00721 data = lookup_specialization_data (gtype);
00722 g_return_val_if_fail (data != NULL, FALSE);
00723
00724 return ((DBusGTypeSpecializedCollectionVtable *) (data->klass->vtable))->fixed_accessor (gtype,
00725 g_value_get_boxed (value),
00726 data_ret, len_ret);
00727 }
00728
00740 void
00741 dbus_g_type_collection_value_iterate (const GValue *value,
00742 DBusGTypeSpecializedCollectionIterator iterator,
00743 gpointer user_data)
00744 {
00745 DBusGTypeSpecializedData *data;
00746 GType gtype;
00747
00748 g_return_if_fail (specialized_types_is_initialized ());
00749 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00750
00751 gtype = G_VALUE_TYPE (value);
00752 data = lookup_specialization_data (gtype);
00753 g_return_if_fail (data != NULL);
00754
00755 ((DBusGTypeSpecializedCollectionVtable *) data->klass->vtable)->iterator (gtype,
00756 g_value_get_boxed (value),
00757 iterator, user_data);
00758 }
00759
00760 typedef struct {
00761 GValue *val;
00762 GType specialization_type;
00763 DBusGTypeSpecializedData *specdata;
00764 } DBusGTypeSpecializedAppendContextReal;
00765
00775 void
00776 dbus_g_type_specialized_init_append (GValue *value, DBusGTypeSpecializedAppendContext *ctx)
00777 {
00778 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00779 GType gtype;
00780 DBusGTypeSpecializedData *specdata;
00781
00782 g_return_if_fail (specialized_types_is_initialized ());
00783 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00784 gtype = G_VALUE_TYPE (value);
00785 specdata = lookup_specialization_data (gtype);
00786 g_return_if_fail (specdata != NULL);
00787 g_return_if_fail (specdata->num_types != 0);
00788
00789 realctx->val = value;
00790 realctx->specialization_type = specdata->types[0];
00791 realctx->specdata = specdata;
00792 }
00793
00802 void
00803 dbus_g_type_specialized_collection_append (DBusGTypeSpecializedAppendContext *ctx,
00804 GValue *elt)
00805 {
00806 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00807 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->append_func (ctx, elt);
00808 }
00809
00817 void
00818 dbus_g_type_specialized_collection_end_append (DBusGTypeSpecializedAppendContext *ctx)
00819 {
00820 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00821 if (((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func != NULL)
00822 ((DBusGTypeSpecializedCollectionVtable *) realctx->specdata->klass->vtable)->end_append_func (ctx);
00823 }
00824
00834 void
00835 dbus_g_type_specialized_map_append (DBusGTypeSpecializedAppendContext *ctx,
00836 GValue *key,
00837 GValue *val)
00838 {
00839 DBusGTypeSpecializedAppendContextReal *realctx = (DBusGTypeSpecializedAppendContextReal *) ctx;
00840 ((DBusGTypeSpecializedMapVtable *) realctx->specdata->klass->vtable)->append_func (ctx, key, val);
00841 }
00842
00843
00855 void
00856 dbus_g_type_map_value_iterate (const GValue *value,
00857 DBusGTypeSpecializedMapIterator iterator,
00858 gpointer user_data)
00859 {
00860 DBusGTypeSpecializedData *data;
00861 GType gtype;
00862
00863 g_return_if_fail (specialized_types_is_initialized ());
00864 g_return_if_fail (G_VALUE_HOLDS_BOXED (value));
00865
00866 gtype = G_VALUE_TYPE (value);
00867 data = lookup_specialization_data (gtype);
00868 g_return_if_fail (data != NULL);
00869
00870 ((DBusGTypeSpecializedMapVtable *) data->klass->vtable)->iterator (gtype,
00871 g_value_get_boxed (value),
00872 iterator, user_data);
00873 }
00874
00887 gboolean
00888 dbus_g_type_struct_get_member (const GValue *value,
00889 guint member,
00890 GValue *dest)
00891 {
00892 DBusGTypeSpecializedData *data;
00893 GType gtype;
00894
00895 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00896 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
00897
00898 gtype = G_VALUE_TYPE (value);
00899 data = lookup_specialization_data (gtype);
00900 g_return_val_if_fail (data != NULL, FALSE);
00901
00902 return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->get_member(gtype,
00903 g_value_get_boxed (value),
00904 member, dest);
00905 }
00906
00918 gboolean
00919 dbus_g_type_struct_set_member (GValue *value,
00920 guint member,
00921 const GValue *src)
00922 {
00923 DBusGTypeSpecializedData *data;
00924 GType gtype;
00925
00926 g_return_val_if_fail (specialized_types_is_initialized (), FALSE);
00927 g_return_val_if_fail (G_VALUE_HOLDS_BOXED (value), FALSE);
00928
00929 gtype = G_VALUE_TYPE (value);
00930 data = lookup_specialization_data (gtype);
00931 g_return_val_if_fail (data != NULL, FALSE);
00932
00933 return ((DBusGTypeSpecializedStructVtable *) (data->klass->vtable))->set_member(gtype,
00934 g_value_get_boxed (value),
00935 member, src);
00936 }
00937
00952 gboolean
00953 dbus_g_type_struct_get (const GValue *value,
00954 guint first_member,
00955 ...)
00956 {
00957 va_list var_args;
00958 GType type;
00959 guint size,i;
00960 gchar *error;
00961 GValue val = {0,};
00962
00963 g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
00964
00965 va_start (var_args, first_member);
00966 size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
00967 i = first_member;
00968 while (i != G_MAXUINT)
00969 {
00970 if (i >= size)
00971 goto error;
00972
00973 type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
00974
00975 g_value_init (&val, type);
00976 dbus_g_type_struct_get_member (value, i, &val);
00977
00978 G_VALUE_LCOPY (&val, var_args, 0, &error);
00979 if (error)
00980 {
00981 g_warning ("%s, %s", G_STRFUNC, error);
00982 g_free (error);
00983 g_value_unset (&val);
00984 goto error;
00985 }
00986 g_value_unset (&val);
00987 i = va_arg (var_args, guint);
00988 }
00989 va_end (var_args);
00990 return TRUE;
00991 error:
00992 va_end (var_args);
00993 return FALSE;
00994 }
00995
01008 gboolean
01009 dbus_g_type_struct_set (GValue *value,
01010 guint first_member,
01011 ...)
01012 {
01013 va_list var_args;
01014 GType type;
01015 guint size,i;
01016 gchar *error;
01017 GValue val = {0,};
01018
01019 g_return_val_if_fail (dbus_g_type_is_struct (G_VALUE_TYPE (value)), FALSE);
01020
01021 va_start (var_args, first_member);
01022 size = dbus_g_type_get_struct_size (G_VALUE_TYPE (value));
01023 i = first_member;
01024 while (i != G_MAXUINT)
01025 {
01026 if (i >= size)
01027 goto error;
01028
01029 type = dbus_g_type_get_struct_member_type (G_VALUE_TYPE (value),i);
01030
01031 g_value_init (&val, type);
01032
01033 G_VALUE_COLLECT (&val, var_args, 0, &error);
01034 if (error)
01035 {
01036 g_warning ("%s, %s", G_STRFUNC, error);
01037 g_free (error);
01038 g_value_unset (&val);
01039 goto error;
01040 }
01041
01042 dbus_g_type_struct_set_member (value, i, &val);
01043
01044 g_value_unset (&val);
01045 i = va_arg (var_args, guint);
01046 }
01047 va_end (var_args);
01048 return TRUE;
01049 error:
01050 va_end (var_args);
01051 return FALSE;
01052 }
01053