4d13341c3e
* NEW: GridView.Columns[].Expand is a new property that allows to define if a column automatically expands to fit the GridView visible width, provided that the GridView.AutoResize property is set. If no column has its Expand property set, then the last column will expand anyway. * BUG: Fix a crash in GridView when the gb.gtk component shared library is freed. [GB.QT4] * NEW: GridView.Columns[].Expand is a new property that allows to define if a column automatically expands to fit the GridView visible width, provided that the GridView.AutoResize property is set. If no column has its Expand property set, then the last column will expand anyway. git-svn-id: svn://localhost/gambas/trunk@3953 867c0c6c-44f3-4631-809d-bfa615b0a4ec
1962 lines
33 KiB
C
1962 lines
33 KiB
C
/***************************************************************************
|
||
|
||
gbx_api.c
|
||
|
||
(c) 2000-2011 Benoît 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 2, 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., 51 Franklin Street, Fifth Floor, Boston,
|
||
MA 02110-1301, USA.
|
||
|
||
***************************************************************************/
|
||
|
||
#define __GBX_API_C
|
||
|
||
#include "gb_common.h"
|
||
#include "gb_common_case.h"
|
||
#include "gb_common_buffer.h"
|
||
#include "gb_error.h"
|
||
#include "gb_alloc.h"
|
||
|
||
#include <stdarg.h>
|
||
|
||
#include "gbx_class.h"
|
||
#include "gbx_exec.h"
|
||
#include "gbx_event.h"
|
||
#include "gbx_stack.h"
|
||
#include "gbx_stream.h"
|
||
#include "gbx_library.h"
|
||
#include "gbx_watch.h"
|
||
#include "gbx_project.h"
|
||
#include "gbx_eval.h"
|
||
#include "gbx_local.h"
|
||
#include "gb_hash.h"
|
||
#include "gb_file.h"
|
||
#include "gbx_number.h"
|
||
#include "gbx_object.h"
|
||
#include "gbx_string.h"
|
||
#include "gbx_date.h"
|
||
#include "gbx_regexp.h"
|
||
#include "gbx_c_array.h"
|
||
#include "gbx_c_timer.h"
|
||
#include "gbx_component.h"
|
||
#include "gbx_c_gambas.h"
|
||
#include "gbx_c_observer.h"
|
||
#include "gbx_debug.h"
|
||
#include "gbx_c_file.h"
|
||
|
||
#include "gambas.h"
|
||
#include "gbx_api.h"
|
||
|
||
typedef
|
||
struct {
|
||
OBJECT *object;
|
||
CLASS_DESC_METHOD *desc;
|
||
}
|
||
GB_API_FUNCTION;
|
||
|
||
void *GAMBAS_Api[] =
|
||
{
|
||
(void *)GB_VERSION,
|
||
|
||
(void *)GB_GetInterface,
|
||
|
||
(void *)GB_Hook,
|
||
|
||
(void *)GB_LoadComponent,
|
||
(void *)COMPONENT_exist,
|
||
(void *)GB_CurrentComponent,
|
||
(void *)COMPONENT_get_info,
|
||
|
||
(void *)GB_Push,
|
||
(void *)GB_GetFunction,
|
||
(void *)GB_Call,
|
||
(void *)GB_GetClassInterface,
|
||
(void *)GB_GetProperty,
|
||
(void *)GB_SetProperty,
|
||
|
||
(void *)WATCH_one_loop,
|
||
(void *)EVENT_post,
|
||
(void *)EVENT_post2,
|
||
(void *)CTIMER_every,
|
||
(void *)GB_Raise,
|
||
(void *)EVENT_post_event,
|
||
(void *)EVENT_check_post,
|
||
(void *)GB_CanRaise,
|
||
(void *)GB_GetEvent,
|
||
(void *)GB_GetLastEventName,
|
||
(void *)CTIMER_raise,
|
||
(void *)GB_Stopped,
|
||
(void *)COMPONENT_signal,
|
||
|
||
(void *)GB_NParam,
|
||
(void *)GB_Conv,
|
||
(void *)GB_GetUnknown,
|
||
|
||
(void *)GB_Error,
|
||
(void *)ERROR_propagate,
|
||
|
||
(void *)GB_GetClass,
|
||
(void *)GB_GetClassName,
|
||
(void *)GB_ExistClass,
|
||
(void *)CLASS_find_global,
|
||
(void *)GB_ExistClassLocal,
|
||
(void *)CLASS_find,
|
||
(void *)GB_Is,
|
||
(void *)GB_Ref,
|
||
(void *)GB_Unref,
|
||
(void *)GB_UnrefKeep,
|
||
(void *)GB_Detach,
|
||
(void *)GB_Attach,
|
||
(void *)OBJECT_parent,
|
||
(void *)GB_New,
|
||
(void *)CLASS_auto_create,
|
||
(void *)GB_CheckObject,
|
||
|
||
(void *)GB_GetEnum,
|
||
(void *)GB_StopEnum,
|
||
(void *)GB_ListEnum,
|
||
(void *)GB_NextEnum,
|
||
(void *)GB_StopAllEnum,
|
||
|
||
(void *)GB_Return,
|
||
(void *)GB_ReturnInteger,
|
||
(void *)GB_ReturnLong,
|
||
(void *)GB_ReturnPointer,
|
||
(void *)GB_ReturnBoolean,
|
||
(void *)GB_ReturnDate,
|
||
(void *)GB_ReturnObject,
|
||
(void *)GB_ReturnNull,
|
||
(void *)GB_ReturnFloat,
|
||
(void *)GB_ReturnPtr,
|
||
(void *)GB_ReturnSelf,
|
||
|
||
(void *)GB_ReturnString,
|
||
(void *)GB_ReturnConstString,
|
||
(void *)GB_ReturnConstZeroString,
|
||
(void *)GB_ReturnNewString,
|
||
(void *)GB_ReturnNewZeroString,
|
||
|
||
(void *)STRING_new,
|
||
(void *)GB_NewZeroString,
|
||
(void *)GB_TempString,
|
||
(void *)GB_FreeString,
|
||
(void *)STRING_extend,
|
||
(void *)STRING_add,
|
||
(void *)GB_StringLength,
|
||
(void *)GB_ToZeroString,
|
||
(void *)REGEXP_match,
|
||
(void *)NUMBER_from_string,
|
||
(void *)GB_NumberToString,
|
||
(void *)LOCAL_gettext,
|
||
|
||
(void *)STRING_subst,
|
||
(void *)STRING_subst_add,
|
||
(void *)STRING_make,
|
||
(void *)GB_ConvString,
|
||
(void *)STRING_conv_file_name,
|
||
(void *)GB_RealFileName,
|
||
|
||
(void *)GB_LoadFile,
|
||
(void *)STREAM_unmap,
|
||
(void *)GB_TempDir,
|
||
(void *)GB_TempFile,
|
||
(void *)GB_CopyFile,
|
||
(void *)GB_BrowseProject,
|
||
|
||
(void *)GB_Store,
|
||
(void *)GB_StoreString,
|
||
(void *)GB_StoreObject,
|
||
(void *)GB_StoreVariant,
|
||
(void *)VALUE_read,
|
||
(void *)GB_BorrowValue,
|
||
(void *)GB_ReleaseValue,
|
||
|
||
(void *)DATE_split,
|
||
(void *)DATE_make,
|
||
(void *)DATE_from_time,
|
||
(void *)DATE_timer,
|
||
|
||
(void *)GB_Watch,
|
||
|
||
(void *)GB_Eval,
|
||
|
||
(void *)GB_Alloc,
|
||
(void *)GB_Free,
|
||
(void *)GB_Realloc,
|
||
|
||
(void *)GB_NewArray,
|
||
(void *)ARRAY_delete,
|
||
(void *)GB_CountArray,
|
||
(void *)GB_Add,
|
||
(void *)ARRAY_insert_many,
|
||
(void *)ARRAY_remove_many,
|
||
|
||
(void *)GB_SubCollectionNew,
|
||
(void *)GB_SubCollectionAdd,
|
||
(void *)GB_SubCollectionRemove,
|
||
(void *)GB_SubCollectionGet,
|
||
(void *)GB_SubCollectionContainer,
|
||
|
||
(void *)GB_tolower,
|
||
(void *)GB_toupper,
|
||
(void *)strcasecmp,
|
||
(void *)strncasecmp,
|
||
|
||
(void *)GB_AppName,
|
||
(void *)GB_AppTitle,
|
||
(void *)GB_AppVersion,
|
||
(void *)GB_AppPath,
|
||
(void *)GB_AppStartupClass,
|
||
|
||
(void *)GB_SystemCharset,
|
||
(void *)LOCAL_get_lang,
|
||
(void *)GB_SystemDomainName,
|
||
(void *)GB_IsRightToLeft,
|
||
(void *)GB_SystemPath,
|
||
|
||
(void *)GB_ArrayNew,
|
||
(void *)GB_ArrayCount,
|
||
(void *)GB_ArrayAdd,
|
||
(void *)GB_ArrayGet,
|
||
(void *)GB_ArrayType,
|
||
|
||
(void *)GB_CollectionNew,
|
||
(void *)GB_CollectionCount,
|
||
(void *)GB_CollectionSet,
|
||
(void *)GB_CollectionGet,
|
||
(void *)GB_CollectionEnum,
|
||
|
||
(void *)GB_HashTableNew,
|
||
(void *)HASH_TABLE_delete,
|
||
(void *)HASH_TABLE_size,
|
||
(void *)GB_HashTableAdd,
|
||
(void *)GB_HashTableRemove,
|
||
(void *)GB_HashTableGet,
|
||
(void *)GB_HashTableEnum,
|
||
|
||
(void *)GB_StreamGet,
|
||
(void *)GB_StreamSetBytesRead,
|
||
(void *)GB_StreamSetSwapping,
|
||
(void *)GB_StreamBlock,
|
||
(void *)GB_StreamRead,
|
||
(void *)GB_StreamWrite,
|
||
|
||
(void *)STRING_start_len,
|
||
(void *)STRING_end,
|
||
(void *)STRING_make,
|
||
|
||
(void *)DEBUG_get_current_position,
|
||
|
||
NULL
|
||
};
|
||
|
||
void *GAMBAS_DebugApi[] =
|
||
{
|
||
(void *)GB_DebugGetExec,
|
||
(void *)STACK_get_frame,
|
||
(void *)ERROR_print_at,
|
||
(void *)ERROR_save,
|
||
(void *)ERROR_restore,
|
||
(void *)VALUE_to_string,
|
||
(void *)LOCAL_format_date,
|
||
(void *)LOCAL_format_number,
|
||
(void *)DEBUG_get_value,
|
||
(void *)DEBUG_set_value,
|
||
(void *)CARRAY_get_value,
|
||
(void *)GB_CollectionEnum,
|
||
(void *)CLASS_get_next_sorted_symbol,
|
||
(void *)DEBUG_get_object_access_type,
|
||
(void *)DEBUG_find_class,
|
||
(void *)CARRAY_get_array_bounds,
|
||
NULL
|
||
};
|
||
|
||
|
||
bool GAMBAS_DoNotRaiseEvent = FALSE;
|
||
bool GAMBAS_StopEvent = FALSE;
|
||
|
||
static bool _event_stopped = FALSE;
|
||
|
||
#define CATCH_ERROR \
|
||
bool ret = FALSE; \
|
||
TRY
|
||
|
||
#define END_CATCH_ERROR \
|
||
CATCH \
|
||
{ \
|
||
ret = TRUE; \
|
||
EXEC_set_native_error(TRUE); \
|
||
} \
|
||
END_TRY \
|
||
return ret;
|
||
|
||
#define CATCH_ERROR_INT \
|
||
int ret = 0; \
|
||
TRY
|
||
|
||
#define END_CATCH_ERROR_INT \
|
||
CATCH \
|
||
{ \
|
||
ret = -1; \
|
||
EXEC_set_native_error(TRUE); \
|
||
} \
|
||
END_TRY \
|
||
return ret;
|
||
|
||
bool GB_GetInterface(const char *name, int version, void *iface)
|
||
{
|
||
GB_LoadComponent(name);
|
||
|
||
if (LIBRARY_get_interface_by_name(name, version, iface))
|
||
ERROR_panic("Cannot find interface of library '%s'", name);
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
void *GB_Hook(int type, void *hook)
|
||
{
|
||
void *old_hook;
|
||
void **phook = (void **)(void *)&EXEC_Hook;
|
||
|
||
if ((type < 0) || (type > GB_HOOK_MAX))
|
||
return NULL;
|
||
|
||
type--;
|
||
old_hook = phook[type];
|
||
if (hook)
|
||
phook[type] = hook;
|
||
|
||
return old_hook;
|
||
}
|
||
|
||
|
||
bool GB_LoadComponent(const char *name)
|
||
{
|
||
CATCH_ERROR
|
||
{
|
||
COMPONENT *comp = COMPONENT_create(name);
|
||
COMPONENT_load(comp);
|
||
}
|
||
END_CATCH_ERROR
|
||
}
|
||
|
||
|
||
static void push(int nval, va_list args)
|
||
{
|
||
TYPE type;
|
||
|
||
STACK_check(nval);
|
||
|
||
while (nval)
|
||
{
|
||
type = va_arg(args, int);
|
||
SP->type = type;
|
||
|
||
switch(type)
|
||
{
|
||
case T_INTEGER:
|
||
case T_BOOLEAN:
|
||
SP->_integer.value = va_arg(args, int);
|
||
break;
|
||
|
||
case T_LONG:
|
||
SP->_long.value = va_arg(args, int64_t);
|
||
break;
|
||
|
||
case T_STRING:
|
||
SP->type = T_CSTRING;
|
||
SP->_string.addr = va_arg(args, char *);
|
||
SP->_string.start = 0;
|
||
SP->_string.len = va_arg(args, int);
|
||
if (SP->_string.len <= 0 && SP->_string.addr)
|
||
SP->_string.len = strlen(SP->_string.addr);
|
||
break;
|
||
|
||
case T_FLOAT:
|
||
SP->_float.value = va_arg(args, double);
|
||
break;
|
||
|
||
case T_OBJECT:
|
||
SP->_object.object = va_arg(args, void *);
|
||
OBJECT_REF(SP->_object.object, "push");
|
||
break;
|
||
|
||
default:
|
||
ERROR_panic("GB.Push: unknown datatype");
|
||
break;
|
||
}
|
||
|
||
SP++;
|
||
nval--;
|
||
}
|
||
}
|
||
|
||
|
||
void GB_Push(int nval, ...)
|
||
{
|
||
va_list args;
|
||
|
||
va_start(args, nval);
|
||
push(nval, args);
|
||
va_end(args);
|
||
}
|
||
|
||
|
||
void GB_GetProperty(void *object, const char *property)
|
||
{
|
||
static bool init = FALSE;
|
||
static GB_FUNCTION func;
|
||
|
||
if (!init)
|
||
{
|
||
GB_GetFunction(&func, (void *)CLASS_find("Object"), "GetProperty", NULL, NULL);
|
||
init = TRUE;
|
||
}
|
||
|
||
GB_Push(2, GB_T_OBJECT, object, GB_T_STRING, property, strlen(property));
|
||
GB_Call(&func, 2, FALSE);
|
||
}
|
||
|
||
void GB_SetProperty(void *object, const char *property, ...)
|
||
{
|
||
static bool init = FALSE;
|
||
static GB_FUNCTION func;
|
||
|
||
va_list args;
|
||
|
||
if (!init)
|
||
{
|
||
GB_GetFunction(&func, (void *)CLASS_find("Object"), "SetProperty", NULL, NULL);
|
||
init = TRUE;
|
||
}
|
||
|
||
GB_Push(2, GB_T_OBJECT, object, GB_T_STRING, property, strlen(property));
|
||
|
||
va_start(args, property);
|
||
push(1, args);
|
||
va_end(args);
|
||
|
||
GB_Call(&func, 3, TRUE);
|
||
}
|
||
|
||
|
||
bool GB_CanRaise(void *object, int event_id)
|
||
{
|
||
ushort *event_tab;
|
||
int func_id;
|
||
COBSERVER *obs;
|
||
|
||
if (!object || !OBJECT_has_events(object))
|
||
return FALSE;
|
||
|
||
LIST_for_each(obs, OBJECT_event(object)->observer)
|
||
{
|
||
if (OBJECT_active_parent(obs) && obs->event && obs->event[event_id])
|
||
return TRUE;
|
||
}
|
||
|
||
if (!OBJECT_active_parent(object))
|
||
return FALSE;
|
||
|
||
event_tab = OBJECT_event(object)->event;
|
||
func_id = event_tab[event_id];
|
||
|
||
return (func_id != 0);
|
||
}
|
||
|
||
|
||
static int get_event_func_id(ushort *event_tab, int event_id)
|
||
{
|
||
int func_id;
|
||
|
||
if (!event_tab)
|
||
return 0;
|
||
|
||
func_id = event_tab[event_id];
|
||
if (!func_id)
|
||
return 0;
|
||
|
||
return func_id;
|
||
}
|
||
|
||
static bool raise_event(OBJECT *observer, void *object, int func_id, int nparam)
|
||
{
|
||
bool stop_event;
|
||
CLASS *class;
|
||
CLASS_DESC_METHOD *desc;
|
||
void *old_last;
|
||
bool result;
|
||
|
||
func_id--;
|
||
|
||
if (OBJECT_is_class(observer))
|
||
class = (CLASS *)observer; //OBJECT_class(object);
|
||
else
|
||
class = OBJECT_class(observer);
|
||
|
||
desc = &class->table[func_id].desc->method;
|
||
|
||
old_last = EVENT_Last;
|
||
EVENT_Last = object;
|
||
//OBJECT_REF(object, "raise_event");
|
||
|
||
// if (arg)
|
||
// {
|
||
// EXEC_dup(nparam);
|
||
// }
|
||
// else
|
||
// {
|
||
// va_start(args, nparam);
|
||
// push(nparam, args);
|
||
// va_end(args);
|
||
// }
|
||
|
||
stop_event = GAMBAS_StopEvent;
|
||
GAMBAS_StopEvent = FALSE;
|
||
|
||
EXEC_public_desc(class, observer, desc, nparam);
|
||
|
||
if (RP->type == T_VOID)
|
||
result = FALSE;
|
||
else
|
||
result = RP->_boolean.value != 0;
|
||
|
||
if (GAMBAS_StopEvent)
|
||
result = TRUE;
|
||
|
||
GAMBAS_StopEvent = stop_event;
|
||
|
||
//OBJECT_UNREF(object, "raise_event");
|
||
EVENT_Last = old_last;
|
||
|
||
EXEC_release_return_value();
|
||
|
||
return result;
|
||
}
|
||
|
||
// If nparam < 0, the args are already on the stack
|
||
|
||
bool GB_Raise(void *object, int event_id, int nparam, ...)
|
||
{
|
||
OBJECT *parent;
|
||
int func_id;
|
||
int result;
|
||
va_list args;
|
||
bool arg;
|
||
COBSERVER *obs;
|
||
|
||
if (GAMBAS_DoNotRaiseEvent)
|
||
return FALSE;
|
||
|
||
if (!OBJECT_is_valid(object) || !OBJECT_has_events(object))
|
||
return FALSE;
|
||
|
||
/*TRY
|
||
{*/
|
||
OBJECT_REF(object, "GB_Raise");
|
||
|
||
arg = nparam < 0;
|
||
nparam = abs(nparam);
|
||
|
||
if (!arg)
|
||
{
|
||
va_start(args, nparam);
|
||
push(nparam, args);
|
||
va_end(args);
|
||
}
|
||
|
||
result = FALSE;
|
||
|
||
// Observers before
|
||
|
||
LIST_for_each(obs, OBJECT_event(object)->observer)
|
||
{
|
||
parent = OBJECT_active_parent(obs);
|
||
if (!parent)
|
||
continue;
|
||
if (obs->after)
|
||
continue;
|
||
//if (obs->object != object)
|
||
// continue;
|
||
|
||
func_id = get_event_func_id(obs->event, event_id);
|
||
if (!func_id)
|
||
continue;
|
||
|
||
if (!OBJECT_is_valid(parent))
|
||
{
|
||
OBJECT_detach(object);
|
||
continue;
|
||
}
|
||
|
||
EXEC_dup(nparam);
|
||
result = raise_event(parent, object, func_id, nparam);
|
||
|
||
if (result)
|
||
goto __RETURN;
|
||
}
|
||
|
||
// Parent
|
||
|
||
parent = OBJECT_active_parent(object);
|
||
if (parent)
|
||
{
|
||
func_id = get_event_func_id(OBJECT_event(object)->event, event_id);
|
||
if (func_id)
|
||
{
|
||
#if DEBUG_EVENT
|
||
CLASS *class = OBJECT_class(object);
|
||
printf("GB_Raise(%p, %d, %s)\n", object, event_id, class->event[event_id].name);
|
||
printf("func_id = %d parent = (%s %p)\n", func_id, parent->class->name, parent);
|
||
if (OBJECT_is_locked(parent))
|
||
printf("parent is locked!\n");
|
||
fflush(NULL);
|
||
#endif
|
||
|
||
if (!OBJECT_is_valid(parent))
|
||
OBJECT_detach(object);
|
||
else
|
||
{
|
||
EXEC_dup(nparam);
|
||
result = raise_event(parent, object, func_id, nparam);
|
||
if (result)
|
||
goto __RETURN;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Observers after
|
||
|
||
LIST_for_each(obs, OBJECT_event(object)->observer)
|
||
{
|
||
parent = OBJECT_active_parent(obs);
|
||
if (!parent)
|
||
continue;
|
||
if (!obs->after)
|
||
continue;
|
||
//if (obs->object != object)
|
||
// continue;
|
||
|
||
func_id = get_event_func_id(obs->event, event_id);
|
||
if (!func_id)
|
||
continue;
|
||
|
||
if (!OBJECT_is_valid(parent))
|
||
{
|
||
OBJECT_detach(object);
|
||
continue;
|
||
}
|
||
|
||
EXEC_dup(nparam);
|
||
result = raise_event(parent, object, func_id, nparam);
|
||
if (result)
|
||
goto __RETURN;
|
||
}
|
||
|
||
__RETURN:
|
||
|
||
RELEASE_MANY(SP, nparam);
|
||
OBJECT_UNREF(object, "GB_Raise");
|
||
/*}
|
||
CATCH
|
||
{
|
||
RELEASE_MANY(SP, nparam);
|
||
OBJECT_UNREF(object, "GB_Raise");
|
||
PROPAGATE();
|
||
}
|
||
END_TRY*/
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
bool GB_GetFunction(GB_FUNCTION *_func, void *object, const char *name, const char *sign, const char *type)
|
||
{
|
||
GB_API_FUNCTION *func = (GB_API_FUNCTION *)_func;
|
||
char len_min, nparam, npvar;
|
||
TYPE *tsign;
|
||
TYPE tret;
|
||
int index;
|
||
CLASS *class;
|
||
int kind;
|
||
CLASS_DESC *desc;
|
||
bool error;
|
||
|
||
if (OBJECT_is_class(object))
|
||
{
|
||
class = (CLASS *)object;
|
||
kind = CD_STATIC_METHOD;
|
||
}
|
||
else
|
||
{
|
||
class = OBJECT_class(object);
|
||
kind = CD_METHOD;
|
||
}
|
||
|
||
CLASS_load(class);
|
||
|
||
index = CLASS_find_symbol(class, name);
|
||
if (index == NO_SYMBOL)
|
||
goto _NOT_FOUND;
|
||
|
||
desc = class->table[index].desc;
|
||
if (CLASS_DESC_get_type(desc) != kind)
|
||
goto _NOT_FOUND;
|
||
|
||
if (sign)
|
||
{
|
||
TYPE_signature_length(sign, &len_min, &nparam, &npvar);
|
||
tsign = NULL;
|
||
|
||
if (nparam)
|
||
{
|
||
ALLOC(&tsign, nparam * sizeof(TYPE), "GB_GetFunction");
|
||
tsign = TYPE_transform_signature(&tsign, sign, nparam);
|
||
}
|
||
|
||
error = TYPE_compare_signature(desc->method.signature, desc->method.npmax, tsign, nparam);
|
||
|
||
if (nparam)
|
||
FREE(&tsign, "GB_GetFunction");
|
||
|
||
if (error)
|
||
{
|
||
GB_Error("Parameters do not match");
|
||
goto _NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
if (type)
|
||
{
|
||
tret = TYPE_from_string(&type);
|
||
if (tret != desc->method.type)
|
||
{
|
||
if (tret == T_VOID)
|
||
GB_Error("Must be a procedure");
|
||
else if (desc->method.type == T_VOID)
|
||
GB_Error("Must be a function");
|
||
else
|
||
GB_Error("Return type does not match");
|
||
|
||
goto _NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
func->object = object;
|
||
func->desc = &desc->method;
|
||
|
||
if (!func->desc)
|
||
abort();
|
||
|
||
return FALSE;
|
||
|
||
_NOT_FOUND:
|
||
|
||
func->object = NULL;
|
||
func->desc = NULL;
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
void *GB_GetClassInterface(void *_class, const char *_name)
|
||
{
|
||
CLASS_DESC *desc;
|
||
int index;
|
||
CLASS *class = (CLASS *)_class;
|
||
int len = strlen(_name);
|
||
char name[len + 4];
|
||
|
||
CLASS_load(class);
|
||
|
||
strcpy(name, "_@");
|
||
strcat(name, _name);
|
||
|
||
index = CLASS_find_symbol(class, name);
|
||
if (index == NO_SYMBOL)
|
||
goto __NOT_FOUND;
|
||
|
||
desc = class->table[index].desc;
|
||
if (CLASS_DESC_get_type(desc) != CD_CONSTANT)
|
||
goto __NOT_FOUND;
|
||
|
||
if (desc->constant.type != T_POINTER)
|
||
goto __NOT_FOUND;
|
||
|
||
return desc->constant.value._pointer;
|
||
|
||
__NOT_FOUND:
|
||
return NULL;
|
||
}
|
||
|
||
|
||
GB_VALUE *GB_Call(GB_FUNCTION *_func, int nparam, int release)
|
||
{
|
||
GB_API_FUNCTION *func = (GB_API_FUNCTION *)_func;
|
||
bool stop_event;
|
||
|
||
if (!func || !func->desc)
|
||
GB_Error("Unknown function call");
|
||
//TEMP.type = GB_T_NULL;
|
||
else
|
||
{
|
||
stop_event = GAMBAS_StopEvent;
|
||
EXEC_public_desc(func->desc->class, func->object, func->desc, nparam);
|
||
_event_stopped = GAMBAS_StopEvent;
|
||
GAMBAS_StopEvent = stop_event;
|
||
|
||
if (release)
|
||
EXEC_release_return_value();
|
||
else
|
||
{
|
||
UNBORROW(RP);
|
||
TEMP = *RP;
|
||
RP->type = T_VOID;
|
||
}
|
||
}
|
||
|
||
return (GB_VALUE *)&TEMP;
|
||
}
|
||
|
||
|
||
int GB_GetEvent(void *class, char *name)
|
||
{
|
||
CLASS_DESC_EVENT *cd;
|
||
|
||
cd = CLASS_get_event_desc((CLASS *)class, name);
|
||
if (!cd)
|
||
return (-1);
|
||
else
|
||
return *cd->index;
|
||
}
|
||
|
||
|
||
char *GB_GetLastEventName()
|
||
{
|
||
return EVENT_Name;
|
||
}
|
||
|
||
|
||
bool GB_Stopped(void)
|
||
{
|
||
return _event_stopped;
|
||
}
|
||
|
||
|
||
int GB_NParam(void)
|
||
{
|
||
return EXEC_unknown_nparam;
|
||
}
|
||
|
||
|
||
/*bool GB_IsProperty(void)
|
||
{
|
||
return FALSE; //EXEC_unknown_property;
|
||
}*/
|
||
|
||
|
||
const char *GB_GetUnknown(void)
|
||
{
|
||
return EXEC_unknown_name;
|
||
}
|
||
|
||
|
||
void GB_Error(const char *error, ...)
|
||
{
|
||
va_list args;
|
||
char *arg[4];
|
||
int i;
|
||
|
||
if (!error)
|
||
{
|
||
EXEC_set_native_error(FALSE);
|
||
return;
|
||
}
|
||
|
||
va_start(args, error);
|
||
|
||
for (i = 0; i < 4; i++)
|
||
arg[i] = va_arg(args, char *);
|
||
|
||
ERROR_define(error, arg);
|
||
EXEC_set_native_error(TRUE);
|
||
}
|
||
|
||
#if DEBUG_REF
|
||
|
||
#include <execinfo.h>
|
||
|
||
static void print_stack_backtrace()
|
||
{
|
||
void *trace[16];
|
||
char **messages = (char **)NULL;
|
||
int i, trace_size = 0;
|
||
|
||
trace_size = backtrace(trace, 16);
|
||
messages = backtrace_symbols(trace, trace_size);
|
||
//printf("[bt] Execution path:\n");
|
||
for (i=0; i<trace_size; ++i)
|
||
fprintf(stderr, "[bt] %s\n", messages[i]);
|
||
}
|
||
|
||
#endif
|
||
|
||
|
||
void GB_Ref(void *object)
|
||
{
|
||
#if TRACE_MEMORY
|
||
CLASS *save = CP;
|
||
CP = NULL;
|
||
#endif
|
||
|
||
if (object)
|
||
{
|
||
#if DEBUG_REF
|
||
//print_stack_backtrace();
|
||
#endif
|
||
OBJECT_REF(object, "GB_Ref");
|
||
}
|
||
|
||
#if TRACE_MEMORY
|
||
CP = save;
|
||
#endif
|
||
}
|
||
|
||
|
||
void GB_Unref(void **object)
|
||
{
|
||
#if TRACE_MEMORY
|
||
CLASS *save = CP;
|
||
CP = NULL;
|
||
#endif
|
||
|
||
if (*object)
|
||
{
|
||
#if DEBUG_REF
|
||
//print_stack_backtrace();
|
||
#endif
|
||
OBJECT_UNREF(*object, "GB_Unref");
|
||
}
|
||
|
||
#if TRACE_MEMORY
|
||
CP = save;
|
||
#endif
|
||
}
|
||
|
||
|
||
void GB_UnrefKeep(void **object, int delete)
|
||
{
|
||
#if TRACE_MEMORY
|
||
CLASS *save = CP;
|
||
CP = NULL;
|
||
#endif
|
||
|
||
if (*object != NULL)
|
||
{
|
||
#if DEBUG_REF
|
||
//print_stack_backtrace();
|
||
#endif
|
||
if (delete)
|
||
{
|
||
OBJECT_UNREF(*object, "GB_UnrefKeep");
|
||
}
|
||
else
|
||
{
|
||
OBJECT_UNREF_KEEP(*object, "GB_UnrefKeep");
|
||
}
|
||
}
|
||
|
||
#if TRACE_MEMORY
|
||
CP = save;
|
||
#endif
|
||
}
|
||
|
||
|
||
void GB_Detach(void *object)
|
||
{
|
||
if (object)
|
||
{
|
||
#if DEBUG_REF
|
||
//print_stack_backtrace();
|
||
#endif
|
||
OBJECT_detach(object);
|
||
}
|
||
}
|
||
|
||
|
||
void GB_Attach(void *object, void *parent, const char *name)
|
||
{
|
||
if (object)
|
||
{
|
||
#if DEBUG_REF
|
||
//print_stack_backtrace();
|
||
#endif
|
||
OBJECT_attach(object, parent, name);
|
||
}
|
||
}
|
||
|
||
|
||
void GB_StopEnum(void)
|
||
{
|
||
/* Do not forget than event if we stop the enumeration, the return value
|
||
of _next will be converted
|
||
*/
|
||
//VALUE_default(&TEMP, *GAMBAS_ReturnType);
|
||
TEMP.type = T_VOID;
|
||
EXEC_enum->stop = TRUE;
|
||
}
|
||
|
||
|
||
void *GB_GetEnum(void)
|
||
{
|
||
return (void *)&EXEC_enum->data;
|
||
}
|
||
|
||
|
||
static void *_enum_object;
|
||
|
||
void GB_ListEnum(void *enum_object)
|
||
{
|
||
EXEC_enum = NULL;
|
||
_enum_object = enum_object;
|
||
}
|
||
|
||
|
||
bool GB_NextEnum(void)
|
||
{
|
||
for(;;)
|
||
{
|
||
EXEC_enum = CENUM_get_next(EXEC_enum);
|
||
if (!EXEC_enum)
|
||
return TRUE;
|
||
if (EXEC_enum->enum_object == _enum_object)
|
||
return FALSE;
|
||
}
|
||
}
|
||
|
||
void GB_StopAllEnum(void *enum_object)
|
||
{
|
||
GB_ListEnum(enum_object);
|
||
while (!GB_NextEnum())
|
||
GB_StopEnum();
|
||
}
|
||
|
||
|
||
void GB_Return(GB_TYPE type, ...)
|
||
{
|
||
static void *jump[16] = {
|
||
&&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE,
|
||
&&__STRING, &&__STRING, &&__POINTER, &&__VARIANT, &&__FUNCTION, &&__CLASS, &&__NULL
|
||
};
|
||
|
||
VALUE *ret = &TEMP;
|
||
va_list args;
|
||
|
||
va_start(args, type);
|
||
|
||
ret->type = type;
|
||
if (TYPE_is_object(type))
|
||
goto __OBJECT;
|
||
else
|
||
goto *jump[type];
|
||
|
||
__BOOLEAN:
|
||
|
||
ret->_integer.value = va_arg(args, int) ? (-1) : 0;
|
||
goto __CONV;
|
||
|
||
__BYTE:
|
||
|
||
ret->_integer.value = va_arg(args, int);
|
||
goto __CONV;
|
||
|
||
__SHORT:
|
||
|
||
ret->_integer.value = va_arg(args, int);
|
||
goto __CONV;
|
||
|
||
__INTEGER:
|
||
|
||
ret->_integer.value = va_arg(args, int);
|
||
goto __CONV;
|
||
|
||
__LONG:
|
||
|
||
ret->_long.value = va_arg(args, int64_t);
|
||
goto __CONV;
|
||
|
||
__SINGLE:
|
||
|
||
ret->_single.value = va_arg(args, double);
|
||
goto __CONV;
|
||
|
||
__FLOAT:
|
||
|
||
ret->_float.value = va_arg(args, double);
|
||
goto __CONV;
|
||
|
||
__DATE:
|
||
|
||
ret->_date.date = va_arg(args, int);
|
||
ret->_date.time = va_arg(args, int);
|
||
goto __CONV;
|
||
|
||
__OBJECT:
|
||
|
||
ret->_object.object = va_arg(args, void *);
|
||
goto __CONV;
|
||
|
||
__POINTER:
|
||
|
||
ret->_pointer.value = va_arg(args, void *);
|
||
goto __CONV;
|
||
|
||
__CLASS:
|
||
ret->_class.class = va_arg(args, CLASS *);
|
||
goto __CONV;
|
||
|
||
__CONV:
|
||
__STRING:
|
||
__VOID:
|
||
__VARIANT:
|
||
__FUNCTION:
|
||
__NULL:
|
||
return;
|
||
}
|
||
|
||
|
||
void GB_ReturnInteger(int val)
|
||
{
|
||
TEMP.type = T_INTEGER;
|
||
TEMP._integer.value = val;
|
||
}
|
||
|
||
|
||
void GB_ReturnLong(int64_t val)
|
||
{
|
||
TEMP.type = T_LONG;
|
||
TEMP._long.value = val;
|
||
}
|
||
|
||
|
||
void GB_ReturnPointer(void *val)
|
||
{
|
||
TEMP.type = T_POINTER;
|
||
TEMP._pointer.value = val;
|
||
}
|
||
|
||
|
||
void GB_ReturnSingle(float val)
|
||
{
|
||
TEMP.type = T_SINGLE;
|
||
TEMP._single.value = val;
|
||
}
|
||
|
||
void GB_ReturnFloat(double val)
|
||
{
|
||
TEMP.type = T_FLOAT;
|
||
TEMP._float.value = val;
|
||
}
|
||
|
||
|
||
void GB_ReturnDate(GB_DATE *date)
|
||
{
|
||
TEMP.type = T_DATE;
|
||
TEMP._date.date = date->value.date;
|
||
TEMP._date.time = date->value.time;
|
||
}
|
||
|
||
|
||
void GB_ReturnBoolean(int val)
|
||
{
|
||
TEMP.type = T_BOOLEAN;
|
||
TEMP._boolean.value = val ? -1 : 0;
|
||
}
|
||
|
||
|
||
void GB_ReturnObject(void *val)
|
||
{
|
||
if (val == NULL)
|
||
GB_ReturnNull();
|
||
else
|
||
{
|
||
TEMP.type = T_OBJECT; //OBJECT_class(val);
|
||
TEMP._object.object = val;
|
||
}
|
||
}
|
||
|
||
|
||
void GB_ReturnVariant(GB_VARIANT_VALUE *val)
|
||
{
|
||
TEMP._variant.type = T_VARIANT;
|
||
|
||
if (!val)
|
||
{
|
||
TEMP._variant.vtype = T_NULL;
|
||
}
|
||
else
|
||
{
|
||
//VALUE_read(&TEMP, value, type);
|
||
TEMP._variant.vtype = val->type;
|
||
if (TEMP._variant.vtype == T_VOID)
|
||
TEMP._variant.vtype = T_NULL;
|
||
|
||
VARIANT_copy_value(&TEMP._variant, (VARIANT *)val);
|
||
}
|
||
}
|
||
|
||
|
||
void GB_ReturnPtr(GB_TYPE type, void *value)
|
||
{
|
||
if (type == T_VOID)
|
||
return;
|
||
|
||
if (!value)
|
||
VALUE_default(&TEMP, type);
|
||
else
|
||
VALUE_read(&TEMP, value, type);
|
||
}
|
||
|
||
|
||
void GB_ReturnSelf(void *object)
|
||
{
|
||
if (object)
|
||
GB_ReturnObject(object);
|
||
else
|
||
GB_Return(T_CLASS, NULL);
|
||
}
|
||
|
||
|
||
char *GB_ToZeroString(GB_STRING *src)
|
||
{
|
||
char *str;
|
||
|
||
str = STRING_new_temp(src->value.addr + src->value.start, src->value.len);
|
||
|
||
if (str == NULL)
|
||
return "";
|
||
else
|
||
return str;
|
||
}
|
||
|
||
|
||
void GB_ReturnString(char *str)
|
||
{
|
||
TEMP.type = T_STRING;
|
||
TEMP._string.addr = str;
|
||
TEMP._string.start = 0;
|
||
TEMP._string.len = STRING_length(str);
|
||
|
||
if (TEMP._string.len == 0)
|
||
TEMP._string.addr = 0;
|
||
}
|
||
|
||
|
||
void GB_ReturnConstString(const char *str, int len)
|
||
{
|
||
TEMP.type = T_CSTRING;
|
||
TEMP._string.addr = (char *)str;
|
||
TEMP._string.start = 0;
|
||
TEMP._string.len = len;
|
||
|
||
if (TEMP._string.len == 0)
|
||
TEMP._string.addr = 0;
|
||
}
|
||
|
||
|
||
void GB_ReturnConstZeroString(const char *str)
|
||
{
|
||
int len;
|
||
|
||
if (str)
|
||
len = strlen(str);
|
||
else
|
||
len = 0;
|
||
|
||
GB_ReturnConstString(str, len);
|
||
}
|
||
|
||
|
||
void GB_ReturnNewString(const char *src, int len)
|
||
{
|
||
if (len <= 0)
|
||
{
|
||
if (*src)
|
||
{
|
||
ERROR_warning("please use GB.ReturnNewZeroString() instead of GB.ReturnNewString()");
|
||
len = strlen(src);
|
||
}
|
||
else
|
||
{
|
||
GB_ReturnNull();
|
||
return;
|
||
}
|
||
}
|
||
|
||
GB_ReturnString(STRING_new_temp(src, len));
|
||
}
|
||
|
||
|
||
void GB_ReturnNewZeroString(const char *src)
|
||
{
|
||
GB_ReturnString(STRING_new_temp_zero(src));
|
||
}
|
||
|
||
|
||
void GB_ReturnNull(void)
|
||
{
|
||
TEMP.type = T_NULL;
|
||
}
|
||
|
||
|
||
void *GB_GetClass(void *object)
|
||
{
|
||
if (object)
|
||
return OBJECT_class(object);
|
||
else
|
||
return EXEC.class;
|
||
}
|
||
|
||
|
||
char *GB_GetClassName(void *object)
|
||
{
|
||
CLASS *class = GB_GetClass(object);
|
||
return class->name;
|
||
}
|
||
|
||
|
||
bool GB_Is(void *object, void *class)
|
||
{
|
||
CLASS *ob_class;
|
||
|
||
if (!object)
|
||
return FALSE;
|
||
|
||
ob_class = OBJECT_class(object);
|
||
|
||
return ((ob_class == class) || CLASS_inherits(ob_class, class));
|
||
}
|
||
|
||
|
||
bool GB_LoadFile(const char *path, int lenp, char **addr, int *len)
|
||
{
|
||
bool ret = FALSE;
|
||
|
||
//fprintf(stderr, "GB_LoadFile: %.*s\n", lenp ? lenp : strlen(path), path);
|
||
|
||
TRY
|
||
{
|
||
*addr = 0;
|
||
*len = 0;
|
||
|
||
STREAM_map(STRING_conv_file_name(path, lenp), addr, len);
|
||
}
|
||
CATCH
|
||
{
|
||
if (*addr)
|
||
STREAM_unmap(*addr, *len);
|
||
|
||
EXEC_set_native_error(TRUE);
|
||
ret = TRUE;
|
||
}
|
||
END_TRY
|
||
|
||
return ret;
|
||
}
|
||
|
||
|
||
bool GB_ExistFile(const char *path)
|
||
{
|
||
return FILE_exist(path);
|
||
}
|
||
|
||
|
||
void GB_Store(GB_TYPE type, GB_VALUE *src, void *dst)
|
||
{
|
||
if (src != NULL)
|
||
{
|
||
/* Ne marche que parce que value->type == type apr<70> un VALUE_read()
|
||
Sinon il y'aurait des probl<62>es de r<><72>ences - VALUE_write faisant
|
||
appel <20>VALUE_conv() (ceci est un ancien commentaire)
|
||
|
||
=> src->type doit <20>re <20>al <20>type
|
||
*/
|
||
VALUE_write((VALUE *)src, dst, type);
|
||
}
|
||
else
|
||
{
|
||
VALUE_free(dst, type);
|
||
}
|
||
}
|
||
|
||
|
||
void GB_StoreString(GB_STRING *src, char **dst)
|
||
{
|
||
STRING_unref(dst);
|
||
if (src)
|
||
{
|
||
*dst = STRING_new(src->value.addr + src->value.start, src->value.len);
|
||
}
|
||
else
|
||
*dst = NULL;
|
||
}
|
||
|
||
void GB_StoreObject(GB_OBJECT *src, void **dst)
|
||
{
|
||
void *object;
|
||
|
||
if (src)
|
||
object = src->value;
|
||
else
|
||
object = NULL;
|
||
|
||
if (object)
|
||
OBJECT_REF(object, "GB_StoreObject");
|
||
|
||
OBJECT_UNREF(*dst, "GB_StoreObject");
|
||
*dst = object;
|
||
}
|
||
|
||
void GB_StoreVariant(GB_VARIANT *src, void *dst)
|
||
{
|
||
/*GB_Store(GB_T_VARIANT, (GB_VALUE *)src, dst);*/
|
||
if (src)
|
||
{
|
||
VALUE_write((VALUE *)src, dst, T_VARIANT);
|
||
|
||
/*VARIANT_keep((VARIANT *)&src->value);
|
||
VARIANT_free((VARIANT *)dst);
|
||
*((VARIANT *)dst) = *((VARIANT *)&src->value);*/
|
||
}
|
||
else
|
||
{
|
||
VARIANT_free((VARIANT *)dst);
|
||
((VARIANT *)dst)->type = T_NULL;
|
||
}
|
||
}
|
||
|
||
void GB_BorrowValue(GB_VALUE *value)
|
||
{
|
||
BORROW((VALUE *)value);
|
||
}
|
||
|
||
void GB_ReleaseValue(GB_VALUE *value)
|
||
{
|
||
RELEASE((VALUE *)value);
|
||
}
|
||
|
||
void GB_Watch(int fd, int flag, void *callback, intptr_t param)
|
||
{
|
||
HOOK_DEFAULT(watch, WATCH_watch)(fd, flag, callback, param);
|
||
}
|
||
|
||
|
||
void *GB_New(void *class, const char *name, void *parent)
|
||
{
|
||
void *object;
|
||
|
||
if (name && !parent)
|
||
{
|
||
parent = OP;
|
||
if (!parent)
|
||
parent = CP;
|
||
}
|
||
|
||
if (!((CLASS *)class)->no_create)
|
||
object = OBJECT_create(class, name, parent, 0);
|
||
else
|
||
{
|
||
object = OBJECT_new(class, name, parent);
|
||
OBJECT_UNREF_KEEP(object, "GB_New");
|
||
}
|
||
|
||
return object;
|
||
}
|
||
|
||
|
||
bool GB_CheckObject(void *object)
|
||
{
|
||
CLASS *class;
|
||
|
||
if (object == NULL)
|
||
{
|
||
GB_Error((char *)E_NULL);
|
||
return TRUE;
|
||
}
|
||
|
||
class = OBJECT_class(object);
|
||
|
||
if (class->check && (*(class->check))(object))
|
||
{
|
||
GB_Error((char *)E_IOBJECT);
|
||
return TRUE;
|
||
}
|
||
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
const char *GB_AppName(void)
|
||
{
|
||
return PROJECT_name;
|
||
}
|
||
|
||
const char *GB_AppPath(void)
|
||
{
|
||
return PROJECT_path;
|
||
}
|
||
|
||
const char *GB_AppTitle(void)
|
||
{
|
||
return LOCAL_gettext(PROJECT_title);
|
||
}
|
||
|
||
const char *GB_AppVersion(void)
|
||
{
|
||
return PROJECT_version;
|
||
}
|
||
|
||
void *GB_AppStartupClass(void)
|
||
{
|
||
return PROJECT_class;
|
||
}
|
||
|
||
|
||
void *GB_Eval(void *expr, void *func)
|
||
{
|
||
bool err = EVAL_expression((EXPRESSION *)expr, (EVAL_FUNCTION)func);
|
||
|
||
EXEC_set_native_error(err);
|
||
|
||
if (err)
|
||
return NULL;
|
||
else
|
||
return &TEMP;
|
||
}
|
||
|
||
|
||
void GB_Alloc(void **addr, int len)
|
||
{
|
||
ALLOC(addr, len, "GB_Alloc");
|
||
}
|
||
|
||
void GB_Free(void **addr)
|
||
{
|
||
FREE(addr, "GB_Free");
|
||
}
|
||
|
||
void GB_Realloc(void **addr, int len)
|
||
{
|
||
REALLOC(addr, len, "GB_Realloc");
|
||
}
|
||
|
||
|
||
bool GB_Conv(GB_VALUE *arg, GB_TYPE type)
|
||
{
|
||
CATCH_ERROR
|
||
{
|
||
VALUE_conv((VALUE *)arg, (GB_TYPE)type);
|
||
}
|
||
END_CATCH_ERROR
|
||
}
|
||
|
||
|
||
int GB_StringLength(const char *str)
|
||
{
|
||
return STRING_length(str);
|
||
}
|
||
|
||
|
||
bool GB_NumberToString(int local, double value, const char *format, char **str, int *len)
|
||
{
|
||
return
|
||
LOCAL_format_number
|
||
(
|
||
value,
|
||
format ? LF_USER : LF_GENERAL_NUMBER,
|
||
format,
|
||
format ? strlen(format) : 0,
|
||
str, len, local != 0
|
||
);
|
||
}
|
||
|
||
|
||
void GB_HashTableNew(GB_HASHTABLE *hash, int mode)
|
||
{
|
||
HASH_TABLE_create((HASH_TABLE **)hash, sizeof(void *), mode);
|
||
}
|
||
|
||
void GB_HashTableAdd(GB_HASHTABLE hash, const char *key, int len, void *data)
|
||
{
|
||
if (len <= 0)
|
||
len = strlen(key);
|
||
|
||
*((void **)HASH_TABLE_insert((HASH_TABLE *)hash, key, len)) = data;
|
||
}
|
||
|
||
void GB_HashTableRemove(GB_HASHTABLE hash, const char *key, int len)
|
||
{
|
||
if (len <= 0)
|
||
len = strlen(key);
|
||
|
||
HASH_TABLE_remove((HASH_TABLE *)hash, key, len);
|
||
}
|
||
|
||
bool GB_HashTableGet(GB_HASHTABLE hash, const char *key, int len, void **data)
|
||
{
|
||
void **pdata;
|
||
|
||
if (len <= 0)
|
||
len = strlen(key);
|
||
|
||
pdata = (void **)HASH_TABLE_lookup((HASH_TABLE *)hash, key, len);
|
||
if (pdata)
|
||
{
|
||
*data = *pdata;
|
||
return FALSE;
|
||
}
|
||
else
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
void GB_HashTableEnum(GB_HASHTABLE hash, GB_HASHTABLE_ENUM_FUNC func)
|
||
{
|
||
HASH_ENUM iter;
|
||
void **data;
|
||
|
||
CLEAR(&iter);
|
||
|
||
for(;;)
|
||
{
|
||
data = (void **)HASH_TABLE_next((HASH_TABLE *)hash, &iter);
|
||
if (!data)
|
||
break;
|
||
|
||
(*func)(*data);
|
||
}
|
||
}
|
||
|
||
void GB_NewArray(void *pdata, int size, int count)
|
||
{
|
||
ARRAY_create_with_size(pdata, size, 16);
|
||
if (count)
|
||
ARRAY_add_data(pdata, count, TRUE);
|
||
}
|
||
|
||
|
||
int GB_CountArray(void *data)
|
||
{
|
||
return ARRAY_count(data);
|
||
}
|
||
|
||
|
||
void *GB_Add(void *pdata)
|
||
{
|
||
return ARRAY_add_void_size(pdata);
|
||
}
|
||
|
||
char *GB_NewZeroString(char *src)
|
||
{
|
||
return STRING_new_zero(src);
|
||
}
|
||
|
||
char *GB_TempString(char *src, int len)
|
||
{
|
||
return STRING_new_temp(src, len);
|
||
}
|
||
|
||
void GB_FreeString(char **str)
|
||
{
|
||
STRING_unref(str);
|
||
*str = NULL;
|
||
}
|
||
|
||
bool GB_ConvString(char **result, const char *str, int len, const char *src, const char *dst)
|
||
{
|
||
CATCH_ERROR
|
||
{
|
||
STRING_conv(result, str, len, src, dst, TRUE);
|
||
}
|
||
END_CATCH_ERROR
|
||
}
|
||
|
||
|
||
char *GB_SystemCharset(void)
|
||
{
|
||
return LOCAL_encoding;
|
||
}
|
||
|
||
char *GB_SystemDomainName(void)
|
||
{
|
||
char host[256], domain[256];
|
||
|
||
if (gethostname(host, sizeof(host) - 1))
|
||
return "";
|
||
|
||
if (getdomainname(domain, sizeof(domain) - 1))
|
||
return "";
|
||
|
||
if ((strlen(host) + strlen(domain)) > COMMON_BUF_MAX)
|
||
return "";
|
||
|
||
*COMMON_buffer = 0;
|
||
if (*domain && strcmp(domain, "(none)"))
|
||
{
|
||
strcpy(COMMON_buffer, domain);
|
||
strcat(COMMON_buffer, ".");
|
||
}
|
||
strcat(COMMON_buffer, host);
|
||
|
||
return COMMON_buffer;
|
||
}
|
||
|
||
bool GB_IsRightToLeft(void)
|
||
{
|
||
return LOCAL_local.rtl;
|
||
}
|
||
|
||
char *GB_SystemPath(void)
|
||
{
|
||
return PROJECT_exec_path;
|
||
}
|
||
|
||
/*void GB_StreamInit(GB_STREAM *stream, int fd)
|
||
{
|
||
STREAM *s = (STREAM *)stream;
|
||
|
||
s->type = &STREAM_direct;
|
||
s->direct.fd = fd;
|
||
}*/
|
||
|
||
GB_STREAM *GB_StreamGet(void *object)
|
||
{
|
||
return (GB_STREAM *)CSTREAM_stream(object);
|
||
}
|
||
|
||
void GB_StreamSetBytesRead(GB_STREAM *stream, int length)
|
||
{
|
||
STREAM_eff_read = length;
|
||
}
|
||
|
||
void GB_StreamSetSwapping(GB_STREAM *stream, int swap)
|
||
{
|
||
((STREAM *)stream)->common.swap = swap;
|
||
}
|
||
|
||
bool GB_StreamBlock(GB_STREAM *stream, int block)
|
||
{
|
||
STREAM *st = (STREAM *)stream;
|
||
bool old = STREAM_is_blocking(st);
|
||
STREAM_blocking(st, block);
|
||
return old;
|
||
}
|
||
|
||
int GB_StreamRead(GB_STREAM *stream, void *addr, int len)
|
||
{
|
||
CATCH_ERROR_INT
|
||
{
|
||
if (len < 0)
|
||
ret = STREAM_read_max((STREAM *)stream, addr, -len);
|
||
else
|
||
{
|
||
STREAM_read((STREAM *)stream, addr, len);
|
||
ret = STREAM_eff_read;
|
||
}
|
||
}
|
||
END_CATCH_ERROR_INT
|
||
}
|
||
|
||
int GB_StreamWrite(GB_STREAM *stream, void *addr, int len)
|
||
{
|
||
CATCH_ERROR_INT
|
||
{
|
||
STREAM_write((STREAM *)stream, addr, len);
|
||
ret = len;
|
||
}
|
||
END_CATCH_ERROR_INT
|
||
}
|
||
|
||
int GB_tolower(int c)
|
||
{
|
||
return tolower(c);
|
||
}
|
||
|
||
int GB_toupper(int c)
|
||
{
|
||
return toupper(c);
|
||
}
|
||
|
||
char *GB_TempDir(void)
|
||
{
|
||
return FILE_make_temp(NULL, NULL);
|
||
}
|
||
|
||
char *GB_TempFile(const char *pattern)
|
||
{
|
||
int len;
|
||
return FILE_make_temp(&len, pattern);
|
||
}
|
||
|
||
bool GB_CopyFile(const char *src, const char *dst)
|
||
{
|
||
CATCH_ERROR
|
||
{
|
||
FILE_copy(src, dst);
|
||
}
|
||
END_CATCH_ERROR
|
||
}
|
||
|
||
#if 0
|
||
int GB_FindFile(const char *dir, int recursive, int follow, void (*found)(const char *))
|
||
{
|
||
int ret = 0;
|
||
char *pattern;
|
||
int len_pattern;
|
||
char *str;
|
||
|
||
TRY
|
||
{
|
||
if (recursive)
|
||
FILE_recursive_dir(dir, found, NULL, 0, follow);
|
||
else
|
||
{
|
||
FILE_dir_first(dir, NULL, 0);
|
||
while (!FILE_dir_next(&pattern, &len_pattern))
|
||
{
|
||
if (!LOCAL_is_UTF8)
|
||
{
|
||
if (STRING_conv(&str, pattern, len_pattern, LOCAL_encoding, "UTF-8", FALSE))
|
||
STRING_new(&str, pattern, len_pattern);
|
||
else
|
||
STRING_ref(str);
|
||
}
|
||
else
|
||
STRING_new(&str, pattern, len_pattern);
|
||
|
||
(*found)(str);
|
||
STRING_unref(&str);
|
||
}
|
||
}
|
||
}
|
||
CATCH
|
||
{
|
||
ret = 1;
|
||
GAMBAS_Error = TRUE;
|
||
}
|
||
END_TRY;
|
||
|
||
return ret;
|
||
}
|
||
|
||
int GB_StatFile(const char *path, GB_FILE_STAT *info, int follow)
|
||
{
|
||
int ret = 0;
|
||
|
||
TRY
|
||
{
|
||
FILE_stat(path, (FILE_STAT *)info, follow);
|
||
}
|
||
CATCH
|
||
{
|
||
ret = 1;
|
||
GAMBAS_Error = TRUE;
|
||
}
|
||
END_TRY;
|
||
|
||
return ret;
|
||
}
|
||
#endif
|
||
|
||
char *GB_RealFileName(const char *name, int len)
|
||
{
|
||
char *path = STRING_conv_file_name(name, len);
|
||
char *real;
|
||
char *temp;
|
||
|
||
if (!STREAM_in_archive(path))
|
||
return path;
|
||
|
||
temp = FILE_make_temp(NULL, NULL);
|
||
real = STRING_new_temp(NULL, strlen(temp) + strlen(path) + strlen("/data/"));
|
||
snprintf(real, strlen(temp) + strlen(path) + strlen("/data/") + 1, "%s/data/%s", temp, path);
|
||
|
||
if (!FILE_exist(real))
|
||
{
|
||
TRY
|
||
{
|
||
FILE_make_path_dir(real);
|
||
FILE_copy(path, real);
|
||
}
|
||
CATCH
|
||
{
|
||
real = path;
|
||
}
|
||
END_TRY
|
||
}
|
||
|
||
return real;
|
||
}
|
||
|
||
static GB_BROWSE_CALLBACK _browse_project_func;
|
||
|
||
static void project_file_found(const char *path)
|
||
{
|
||
FILE_STAT info;
|
||
|
||
FILE_stat(path, &info, FALSE);
|
||
(*_browse_project_func)(path, info.size);
|
||
}
|
||
|
||
void GB_BrowseProject(GB_BROWSE_CALLBACK func)
|
||
{
|
||
ARCHIVE *arch = NULL;
|
||
|
||
ARCHIVE_get_current(&arch);
|
||
if (!arch || (arch == ARCHIVE_main && !EXEC_arch))
|
||
{
|
||
_browse_project_func = func;
|
||
FILE_recursive_dir(PROJECT_path, project_file_found, NULL, 0, FALSE);
|
||
}
|
||
else
|
||
ARCHIVE_browse(arch, func);
|
||
}
|
||
|
||
|
||
const char *GB_CurrentComponent()
|
||
{
|
||
ARCHIVE *arch;
|
||
|
||
ARCHIVE_get_current(&arch);
|
||
return arch->name ? arch->name : "";
|
||
}
|
||
|
||
|
||
void *GB_DebugGetExec(void)
|
||
{
|
||
return &EXEC_current;
|
||
}
|
||
|
||
|
||
bool GB_ExistClass(const char *name)
|
||
{
|
||
return CLASS_look_global(name, strlen(name)) != NULL;
|
||
}
|
||
|
||
|
||
bool GB_ExistClassLocal(const char *name)
|
||
{
|
||
return CLASS_look(name, strlen(name)) != NULL;
|
||
}
|