3d80d44a4a
* BUG: Some little layout fixes. [INTERPRETER] * OPT: Read the user home directory only if the current uid has changed. Otherwise, cache it into memory. * OPT: String memory management has been optimized. * OPT: Some little optimizations there and there. * NEW: A new interpreter option, "-k", that prevents shared library to be unloaded until the process terminates. That can be useful when debugging with valgrind. * OPT: System.Language property was optimized. * OPT: The gb_error.c file is now compiled with -O3. [GB.GTK] * BUG: Disable the management of input methods in TextBox and TextArea controls, so that the input methods are not disturbed. Consequently; SCIM and Bridged SCIM work again. * BUG: You can read keyboard events properties in a Form KeyPress or KeyRelease event handler correctly now. git-svn-id: svn://localhost/gambas/trunk@1199 867c0c6c-44f3-4631-809d-bfa615b0a4ec
397 lines
8.1 KiB
C
397 lines
8.1 KiB
C
/***************************************************************************
|
|
|
|
CCollection.c
|
|
|
|
The Collection native class.
|
|
|
|
(c) 2000-2007 Benoit Minisini <gambas@users.sourceforge.net>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 1, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __GBX_C_COLLECTION_C
|
|
|
|
#include "gbx_info.h"
|
|
|
|
#ifndef GBX_INFO
|
|
|
|
#include "gb_common.h"
|
|
#include "gb_error.h"
|
|
|
|
#include "gbx_variant.h"
|
|
#include "gambas.h"
|
|
#include "gbx_api.h"
|
|
#include "gbx_class.h"
|
|
#include "gbx_object.h"
|
|
|
|
#include "gbx_c_collection.h"
|
|
|
|
|
|
static void collection_free(CCOLLECTION *col)
|
|
{
|
|
VARIANT *value;
|
|
HASH_ENUM iter;
|
|
|
|
CLEAR(&iter);
|
|
|
|
for(;;)
|
|
{
|
|
value = HASH_TABLE_next(col->hash_table, &iter);
|
|
if (value == NULL)
|
|
break;
|
|
|
|
VARIANT_free(value);
|
|
}
|
|
|
|
HASH_TABLE_delete(&col->hash_table);
|
|
}
|
|
|
|
static void *collection_get_key(CCOLLECTION *col, const char *key, int len)
|
|
{
|
|
if (!key || !*key)
|
|
{
|
|
GB_Error("Void key");
|
|
return NULL;
|
|
}
|
|
|
|
if (len <= 0)
|
|
len = strlen(key);
|
|
|
|
return HASH_TABLE_lookup(col->hash_table, key, len);
|
|
}
|
|
|
|
|
|
static void *collection_add_key(CCOLLECTION *col, const char *key, int len)
|
|
{
|
|
if (!key || !*key)
|
|
{
|
|
GB_Error("Void key");
|
|
return NULL;
|
|
}
|
|
|
|
if (len <= 0)
|
|
len = strlen(key);
|
|
|
|
return HASH_TABLE_insert(col->hash_table, key, len);
|
|
}
|
|
|
|
|
|
static void collection_remove_key(CCOLLECTION *col, const char *key, int len)
|
|
{
|
|
void *value;
|
|
HASH_NODE *last;
|
|
|
|
if (!key || !*key)
|
|
{
|
|
GB_Error("Void key");
|
|
return;
|
|
}
|
|
|
|
if (len < 0)
|
|
len = strlen(key);
|
|
|
|
value = HASH_TABLE_lookup(col->hash_table, key, len);
|
|
if (value == NULL)
|
|
return;
|
|
|
|
last = col->hash_table->last;
|
|
|
|
GB_ListEnum(col);
|
|
while (!GB_NextEnum())
|
|
{
|
|
HASH_ENUM *iter = (HASH_ENUM *)GB_GetEnum();
|
|
/*char *ekey;
|
|
int elen;
|
|
|
|
HASH_TABLE_get_key(col->hash_table, iter->node, &ekey, &elen);
|
|
fprintf(stderr, "iter->node: %.*s\n", elen, ekey);
|
|
HASH_TABLE_get_key(col->hash_table, iter->next, &ekey, &elen);
|
|
fprintf(stderr, "iter->next: %.*s\n", elen, ekey);*/
|
|
|
|
if (iter->next == last)
|
|
{
|
|
iter->next = iter->next->snext;
|
|
/*HASH_TABLE_get_key(col->hash_table, iter->next, &ekey, &elen);
|
|
fprintf(stderr, "iter->next: => %.*s\n", elen, ekey);*/
|
|
}
|
|
}
|
|
|
|
//col->hash_table->last = last;
|
|
|
|
VARIANT_free(value);
|
|
HASH_TABLE_remove(col->hash_table, key, len);
|
|
}
|
|
|
|
|
|
BEGIN_METHOD(CCOLLECTION_new, GB_INTEGER mode)
|
|
|
|
int mode = MISSING(mode) ? 0 : VARG(mode);
|
|
|
|
HASH_TABLE_create(&THIS->hash_table, TYPE_sizeof(T_VARIANT), mode);
|
|
THIS->last = NULL;
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(CCOLLECTION_free)
|
|
|
|
collection_free(THIS);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_PROPERTY(collection_count)
|
|
|
|
GB_ReturnInt(HASH_TABLE_size(THIS->hash_table));
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_PROPERTY(collection_key)
|
|
|
|
char *key;
|
|
int len;
|
|
|
|
if (HASH_TABLE_get_last_key(THIS->hash_table, &key, &len))
|
|
GB_ReturnNull();
|
|
else
|
|
GB_ReturnNewString(key, len);
|
|
|
|
END_PROPERTY
|
|
|
|
|
|
BEGIN_METHOD(collection_add, GB_VARIANT value; GB_STRING key)
|
|
|
|
void *data;
|
|
|
|
data = collection_add_key(THIS, STRING(key), LENGTH(key));
|
|
if (!data)
|
|
return;
|
|
|
|
GB_StoreVariant(ARG(value), data);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(collection_exist, GB_STRING key)
|
|
|
|
/*if (LENGTH(key) == 0)
|
|
GB_ReturnBoolean(FALSE);
|
|
else*/
|
|
GB_ReturnBoolean(collection_get_key(THIS, STRING(key), LENGTH(key)) != NULL);
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(collection_remove, GB_STRING key)
|
|
|
|
collection_remove_key(THIS, STRING(key), LENGTH(key));
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD_VOID(collection_clear)
|
|
|
|
int mode = THIS->hash_table->mode;
|
|
|
|
/* Stops all iterators */
|
|
GB_StopAllEnum(THIS);
|
|
|
|
collection_free(THIS);
|
|
HASH_TABLE_create(&THIS->hash_table, TYPE_sizeof(T_VARIANT), mode);
|
|
|
|
END_METHOD
|
|
|
|
|
|
#if 0
|
|
BEGIN_METHOD_VOID(collection_first)
|
|
|
|
HASH_ENUM *iter = (HASH_ENUM *)GB_GetEnum();
|
|
|
|
iter->index = (-1);
|
|
iter->node = NULL;
|
|
|
|
END_METHOD
|
|
#endif
|
|
|
|
|
|
BEGIN_METHOD_VOID(collection_next)
|
|
|
|
void *value;
|
|
HASH_TABLE *hash_table = OBJECT(CCOLLECTION)->hash_table;
|
|
HASH_ENUM *iter = (HASH_ENUM *)GB_GetEnum();
|
|
|
|
value = HASH_TABLE_next(hash_table, iter);
|
|
|
|
if (value == NULL)
|
|
GB_StopEnum();
|
|
else
|
|
GB_ReturnPtr(T_VARIANT, value);
|
|
|
|
END_METHOD
|
|
|
|
|
|
/*
|
|
BEGIN_METHOD(collection_copy, CCOLLECTION *copy)
|
|
|
|
CCOLLECTION *copy = PARAM(copy);
|
|
HASH_TABLE *hash_table = THIS->hash_table;
|
|
CCOL_ENUM enum_state;
|
|
void *value;
|
|
|
|
collection_clear(THIS, NULL);
|
|
|
|
enum_state.i = -1;
|
|
enum_state.node = NULL;
|
|
|
|
for(;;)
|
|
{
|
|
value = HASH_TABLE_next(hash_table, &enum_state->i, &enum_state->node);
|
|
if (value == NULL)
|
|
break;
|
|
|
|
GB_ReturnPtr(OBJECT(CCOLLECTION)->type, value);
|
|
data = collection_add_key(THIS, PARAM(key).addr, PARAM(key).len);
|
|
GB_Store(T_VARIANT, &PARAM(value), data);
|
|
|
|
END_METHOD
|
|
*/
|
|
|
|
BEGIN_METHOD(collection_get, GB_STRING key)
|
|
|
|
GB_ReturnPtr(T_VARIANT, collection_get_key(THIS, STRING(key), LENGTH(key)));
|
|
|
|
END_METHOD
|
|
|
|
|
|
BEGIN_METHOD(collection_put, GB_VARIANT value; GB_STRING key)
|
|
|
|
void *data;
|
|
|
|
if (VARIANT_is_null((VARIANT *)&VARG(value)))
|
|
collection_remove_key(THIS, STRING(key), LENGTH(key));
|
|
else
|
|
{
|
|
data = collection_add_key(THIS, STRING(key), LENGTH(key));
|
|
if (!data)
|
|
return;
|
|
GB_StoreVariant(ARG(value), data);
|
|
}
|
|
|
|
END_METHOD
|
|
|
|
#endif
|
|
|
|
|
|
GB_DESC NATIVE_Collection[] =
|
|
{
|
|
GB_DECLARE("Collection", sizeof(CCOLLECTION)),
|
|
|
|
GB_METHOD("_new", NULL, CCOLLECTION_new, "[(Mode)i]"),
|
|
GB_METHOD("_free", NULL, CCOLLECTION_free, NULL),
|
|
|
|
GB_PROPERTY_READ("Count", "i", collection_count),
|
|
GB_PROPERTY_READ("Length", "i", collection_count),
|
|
GB_PROPERTY_READ("Key", "s", collection_key),
|
|
|
|
GB_METHOD("Add", NULL, collection_add, "(Value)v(Key)s"),
|
|
GB_METHOD("Exist", "b", collection_exist, "(Key)s"),
|
|
GB_METHOD("Remove", NULL, collection_remove, "(Key)s"),
|
|
GB_METHOD("Clear", NULL, collection_clear, NULL),
|
|
/*GB_METHOD("_first", NULL, collection_first, NULL),*/
|
|
GB_METHOD("_next", "v", collection_next, NULL),
|
|
GB_METHOD("_get", "v", collection_get, "(Key)s"),
|
|
GB_METHOD("_put", NULL, collection_put, "(Value)v(Key)s"),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
#ifndef GBX_INFO
|
|
|
|
void GB_CollectionNew(GB_COLLECTION *col, int mode)
|
|
{
|
|
GB_INTEGER param;
|
|
|
|
param.type = GB_T_INTEGER;
|
|
param.value = mode;
|
|
|
|
OBJECT_create_native((void **)col, CLASS_Collection, (VALUE *)¶m);
|
|
}
|
|
|
|
int GB_CollectionCount(GB_COLLECTION col)
|
|
{
|
|
return HASH_TABLE_size(((CCOLLECTION *)col)->hash_table);
|
|
}
|
|
|
|
int GB_CollectionSet(GB_COLLECTION col, const char *key, int len, GB_VARIANT *value)
|
|
{
|
|
VARIANT *data;
|
|
|
|
if (VARIANT_is_null((VARIANT *)&value->value))
|
|
collection_remove_key((CCOLLECTION *)col, key, len);
|
|
else
|
|
{
|
|
data = (VARIANT *)collection_add_key((CCOLLECTION *)col, key, len);
|
|
if (!data)
|
|
return TRUE;
|
|
GB_StoreVariant(value, data);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
int GB_CollectionGet(GB_COLLECTION col, const char *key, int len, GB_VARIANT *value)
|
|
{
|
|
void *val;
|
|
|
|
val = collection_get_key((CCOLLECTION *)col, key, len);
|
|
if (val)
|
|
{
|
|
value->type = GB_T_VARIANT;
|
|
//*((VARIANT *)&value->value) = *((VARIANT *)val);
|
|
VARIANT_copy(&value->value, val);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
value->type = GB_T_NULL;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
int GB_CollectionEnum(GB_COLLECTION col, GB_VARIANT *value, char **key, int *len)
|
|
{
|
|
static HASH_ENUM iter;
|
|
void *val;
|
|
HASH_TABLE *hash_table = ((CCOLLECTION *)col)->hash_table;
|
|
|
|
if (!value || !key)
|
|
{
|
|
CLEAR(&iter);
|
|
return FALSE;
|
|
}
|
|
|
|
val = HASH_TABLE_next(hash_table, &iter);
|
|
if (!val)
|
|
return TRUE;
|
|
|
|
value->type = GB_T_VARIANT;
|
|
*((VARIANT *)&value->value) = *((VARIANT *)val);
|
|
|
|
HASH_TABLE_get_last_key(hash_table, key, len);
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|