/*************************************************************************** gbx_api.c Gambas API for external libraries (c) 2000-2007 Benoit Minisini 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_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 #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_print.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 "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_find, (void *)GB_CurrentComponent, (void *)COMPONENT_get_info, (void *)GB_Push, (void *)GB_GetFunction, (void *)GB_Call, (void *)GB_GetClassInterface, (void *)WATCH_one_loop, (void *)EVENT_post, (void *)EVENT_post2, (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_IsProperty, (void *)GB_Error, (void *)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 *)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_ReturnString, (void *)GB_ReturnConstString, (void *)GB_ReturnConstZeroString, (void *)GB_ReturnNewString, (void *)GB_ReturnNewZeroString, (void *)STRING_new, (void *)STRING_new_temp, (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 *)SUBST_add, (void *)GB_ConvString, (void *)STRING_conv_file_name, (void *)GB_RealFileName, (void *)GB_LoadFile, (void *)GB_ReleaseFile, (void *)FILE_exist, (void *)GB_GetTempDir, (void *)GB_Store, (void *)GB_StoreString, (void *)GB_StoreObject, (void *)GB_StoreVariant, (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_PrintData, (void *)PRINT_string, (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_AppStartup, (void *)GB_SystemCharset, (void *)LOCAL_get_lang, (void *)GB_SystemDomainName, (void *)GB_ArrayNew, (void *)GB_ArrayCount, (void *)GB_ArrayAdd, (void *)GB_ArrayGet, (void *)GB_CollectionNew, (void *)GB_CollectionCount, (void *)GB_CollectionSet, (void *)GB_CollectionGet, (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_StreamInit, (void *)GB_ImageCreate, (void *)GB_ImageInfo, (void *)GB_ImageConvert, (void *)GB_PictureCreate, (void *)GB_PictureInfo, 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 *)CARRAY_get_value, (void *)GB_CollectionEnum, (void *)CLASS_get_next_sorted_symbol, (void *)DEBUG_can_be_used_like_an_array, NULL }; TYPE GAMBAS_ReturnType; bool GAMBAS_Error = FALSE; bool GAMBAS_DoNotRaiseEvent = FALSE; bool GAMBAS_StopEvent = FALSE; static bool _event_stopped = FALSE; int GB_GetInterface(const char *name, int version, void *iface) { 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 < GB_HOOK_MAIN) || (type > GB_HOOK_PICTURE)) return NULL; type--; old_hook = phook[type]; phook[type] = hook; return old_hook; } int GB_LoadComponent(const char *name) { int ret = 0; TRY { COMPONENT *comp = COMPONENT_create(name); COMPONENT_load(comp); } CATCH { ret = 1; GAMBAS_Error = TRUE; } END_TRY return ret; } 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); } static void call_method(void *object, CLASS_DESC_METHOD *desc, int nparam) { if (OBJECT_is_class(object)) { EXEC.object = NULL; //EXEC.class = (CLASS *)object; } else { EXEC.object = object; //EXEC.class = OBJECT_class(object); } EXEC.class = desc->class; EXEC.nparam = nparam; /*desc->npmin;*/ EXEC.drop = FALSE; if (FUNCTION_is_native(desc)) { EXEC.native = TRUE; EXEC.use_stack = FALSE; EXEC.desc = desc; EXEC_native(); SP--; *RP = *SP; SP->type = T_VOID; } else { EXEC.native = FALSE; EXEC.index = (int)(intptr_t)desc->exec; EXEC_function_keep(); } } int GB_CanRaise(void *object, int event_id) { ushort *event_tab; int func_id; COBSERVER *obs; if (object == NULL) 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; class = OBJECT_class(object); func_id--; if (OBJECT_is_class(observer)) desc = &(((CLASS *)observer)->table[func_id].desc->method); else desc = &(observer->class->table[func_id].desc->method); old_last = EVENT_Last; EVENT_Last = object; // if (arg) // { // EXEC_dup(nparam); // } // else // { // va_start(args, nparam); // push(nparam, args); // va_end(args); // } stop_event = GAMBAS_StopEvent; GAMBAS_StopEvent = FALSE; call_method(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; EVENT_Last = old_last; EXEC_release_return_value(); return result; } // If nparam < 0, the args are already on the stack int GB_Raise(void *object, int event_id, int nparam, ...) { OBJECT *parent; int func_id; int result; va_list args; bool arg; COBSERVER *obs; bool after = FALSE; /*MEMORY_check_ptr(object);*/ if (GAMBAS_DoNotRaiseEvent) return FALSE; if (object == NULL) return FALSE; OBJECT_REF(object, "GB_Raise"); #if DEBUG_EVENT { CLASS *class = OBJECT_class(object); fprintf(stderr, "GB_Raise(%p, %d, %s)\n", object, event_id, class->event[event_id].name); /*fprintf(stderr, "func_id = %d parent = (%s %p)\n", func_id, parent->class->name, parent); if (OBJECT_is_locked(parent)) fprintf(stderr, "parent is locked!\n");*/ } #endif 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) { after = TRUE; 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 (!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; 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"); return result; } int 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 0; _NOT_FOUND: func->object = NULL; func->desc = NULL; return 1; } 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->desc) GB_Error("Unknown function call"); else { stop_event = GAMBAS_StopEvent; call_method(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; } int GB_Stopped(void) { return _event_stopped; } int GB_NParam(void) { return EXEC.nparvar; } int GB_IsProperty(void) { return EXEC.property; } const char *GB_GetUnknown(void) { return EXEC.unknown; } void GB_Error(const char *error, ...) { va_list args; char *arg[8]; int i; if (!error) { GAMBAS_Error = FALSE; return; } va_start(args, error); for (i = 0; i < 8; i++) arg[i] = va_arg(args, char *); ERROR_define(error, arg); GAMBAS_Error = TRUE; } void GB_Ref(void *object) { #if TRACE_MEMORY CLASS *save = CP; CP = NULL; #endif if (object) 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) 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 (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) OBJECT_detach(object); } void GB_Attach(void *object, void *parent, const char *name) { if (object) 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); 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; } int 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(unsigned int type, ...) { static void *jump[16] = { &&__VOID, &&__BOOLEAN, &&__BYTE, &&__SHORT, &&__INTEGER, &&__LONG, &&__SINGLE, &&__FLOAT, &&__DATE, &&__STRING, &&__STRING, &&__VARIANT, &&__ARRAY, &&__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; __CLASS: ret->_class.class = va_arg(args, CLASS *); goto __CONV; __CONV: /*VALUE_conv(ret, GAMBAS_ReturnType); Laisser l'appelant faire la conversion */ __STRING: __VOID: __VARIANT: __ARRAY: __FUNCTION: __NULL: return; } void GB_ReturnInteger(int val) { GB_Return(T_INTEGER, val); } void GB_ReturnLong(int64_t val) { GB_Return(T_LONG, val); } void GB_ReturnPointer(void *val) { GB_Return(T_POINTER, (intptr_t)val); } void GB_ReturnFloat(double val) { GB_Return(T_FLOAT, val); } void GB_ReturnDate(GB_DATE *date) { TEMP = *((VALUE *)date); TEMP.type = T_DATE; } void GB_ReturnBoolean(int val) { GB_Return(T_BOOLEAN, val); } void GB_ReturnObject(void *val) { if (val == NULL) GB_ReturnNull(); else if (GAMBAS_ReturnType == T_VARIANT) GB_Return(T_OBJECT, val); else GB_Return(GAMBAS_ReturnType, val); } void GB_ReturnPtr(unsigned int type, void *value) { if (type == T_VOID) return; VALUE_read(&TEMP, value, type); /*VALUE_conv(&TEMP, GAMBAS_ReturnType);*/ } char *GB_ToZeroString(GB_STRING *src) { char *str; STRING_new_temp(&str, 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) { char *str; STRING_new_temp(&str, src, len); GB_ReturnString(str); } void GB_ReturnNewZeroString(const char *src) { GB_ReturnNewString(src, 0); } 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; } int 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)); } int GB_LoadFile(const char *path, int lenp, char **addr, int *len) { int ret = 0; //fprintf(stderr, "GB_LoadFile: %.*s\n", lenp ? lenp : strlen(path), path); TRY { *addr = 0; STREAM_map(STRING_conv_file_name(path, lenp), addr, len); } CATCH { if (*addr) GB_ReleaseFile(addr, *len); GAMBAS_Error = TRUE; ret = 1; } END_TRY return ret; } void GB_ReleaseFile(char **addr, int len) { //fprintf(stderr, "GB_ReleaseFile: "); if (ARCHIVE_check_addr(*addr)) { //fprintf(stderr, "free\n"); FREE(addr, "GB_ReleaseFile"); } //else //fprintf(stderr, "unmap\n"); } void GB_Store(GB_TYPE type, GB_VALUE *src, void *dst) { if (src != NULL) { /* Ne marche que parce que value->type == type apr� un VALUE_read() Sinon il y'aurait des probl�es de r��ences - VALUE_write faisant appel �VALUE_conv() (ceci est un ancien commentaire) => src->type doit �re �al �type */ VALUE_write((VALUE *)src, dst, type); } else { VALUE_free(dst, type); } } void GB_StoreString(GB_STRING *src, char **dst) { char *str; STRING_unref(dst); if (src) { STRING_new(&str, src->value.addr + src->value.start, src->value.len); *dst = str; } else *dst = NULL; } void GB_StoreObject(GB_OBJECT *src, void **dst) { void *object; if (src) object = src->value; else object = NULL; if (object) GB_Ref(object); GB_Unref(dst); *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_Watch(int fd, int flag, void *callback, int param) { HOOK_DEFAULT(watch, WATCH_watch)(fd, flag, callback, param); } int GB_New(void **object, void *class, const char *name, void *parent) { if (name && !parent) { parent = OP; if (!parent) parent = CP; } if (!((CLASS *)class)->no_create) OBJECT_create(object, class, name, parent, 0); else { OBJECT_new(object, class, name, parent); OBJECT_UNREF_KEEP(*object, "GB_New"); } return FALSE; } int 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; } const char *GB_AppStartup(void) { return PROJECT_startup; } void *GB_Eval(void *expr, void *func) { GAMBAS_Error = EVAL_expression((EXPRESSION *)expr, (EVAL_FUNCTION)func); if (GAMBAS_Error) 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"); } int GB_Conv(GB_VALUE *arg, GB_TYPE type) { int ret = 0; TRY { VALUE_conv((VALUE *)arg, (GB_TYPE)type); } CATCH { ret = 1; GAMBAS_Error = TRUE; } END_TRY return ret; } int GB_StringLength(const char *str) { return STRING_length(str); } int 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); } int 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 0; } else return 1; } 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); ARRAY_add_data(pdata, count, TRUE); } int GB_CountArray(void *data) { return ARRAY_count(data); } void *GB_Add(void *pdata) { return ARRAY_add_void(pdata); } 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) { bool err = FALSE; TRY { STRING_conv(result, str, len, src, dst, TRUE); } CATCH { err = TRUE; GAMBAS_Error = TRUE; } END_TRY return err; } 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)") != 0) { strcpy(COMMON_buffer, domain); strcat(COMMON_buffer, "."); } strcat(COMMON_buffer, host); return COMMON_buffer; } void GB_StreamInit(GB_STREAM *stream, int fd) { STREAM *s = (STREAM *)stream; s->type = &STREAM_direct; s->direct.fd = fd; } int GB_tolower(int c) { return tolower(c); } int GB_toupper(int c) { return toupper(c); } char *GB_GetTempDir(void) { return FILE_make_temp(NULL, NULL); } 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); STRING_new_temp(&real, NULL, strlen(temp) + strlen(path) + strlen("/data/")); snprintf(real, strlen(temp) + strlen(path) + strlen("/data/"), "%s/data/%s", temp, path); if (!FILE_exist(real)) { TRY { FILE_make_path_dir(real); FILE_copy(path, real); } CATCH { real = path; } END_TRY } //fprintf(stderr, "GB.RealFileName: %s -> %s\n", path, real); return real; } void GB_PrintData(GB_TYPE type, void *addr) { VALUE value; VALUE_read(&value, addr, (TYPE)type); PRINT_value(&value); } const char *GB_CurrentComponent() { ARCHIVE *arch; ARCHIVE_get_current(&arch); return arch->name ? arch->name : ""; } int GB_ImageCreate(GB_IMAGE *image, void *data, int width, int height, int format) { GB_IMAGE_INFO info; if (!EXEC_Hook.image) { GB_Error("No image provider"); return TRUE; } if (image) *image = NULL; info.width = width; info.height = height; info.format = format; info.data = data; return (*EXEC_Hook.image)(image, &info); } void GB_ImageInfo(GB_IMAGE image, GB_IMAGE_INFO *info) { if (!EXEC_Hook.image) { GB_Error("No image provider"); return; } if (image) (*EXEC_Hook.image)(&image, info); } int GB_PictureCreate(GB_PICTURE *picture, void *data, int width, int height, int format) { GB_PICTURE_INFO info; if (!EXEC_Hook.picture) { GB_Error("No picture provider"); return TRUE; } info.width = width; info.height = height; info.format = format; info.data = data; return (*EXEC_Hook.picture)(picture, &info); } void GB_PictureInfo(GB_PICTURE picture, GB_PICTURE_INFO *info) { if (!EXEC_Hook.image) { GB_Error("No image provider"); return; } if (picture) (*EXEC_Hook.picture)(&picture, info); } void *GB_DebugGetExec(void) { return &EXEC_current; } int GB_ExistClass(const char *name) { return CLASS_look_global(name, strlen(name)) != NULL; } int GB_ExistClassLocal(const char *name) { return CLASS_look(name, strlen(name)) != NULL; } void GB_ImageConvert(void *dst, int dst_format, void *src, int src_format, int w, int h) { register char *s = (char *)src; register char *d = (char *)dst; register char *dm = &d[w * h * 4]; if (dst_format == GB_IMAGE_BGRA || dst_format == GB_IMAGE_BGRX) { switch (src_format) { case GB_IMAGE_BGRA: case GB_IMAGE_BGRX: goto __0123; case GB_IMAGE_ARGB: case GB_IMAGE_XRGB: goto __3210; case GB_IMAGE_RGBA: case GB_IMAGE_RGBX: goto __2103; case GB_IMAGE_ABGR: case GB_IMAGE_XBGR: goto __1230; case GB_IMAGE_BGR: goto __012X; case GB_IMAGE_RGB: goto __210X; } } else if (dst_format == GB_IMAGE_RGBA || dst_format == GB_IMAGE_RGBX) { switch (src_format) { case GB_IMAGE_RGBA: case GB_IMAGE_RGBX: goto __0123; case GB_IMAGE_ABGR: case GB_IMAGE_XBGR: goto __3210; case GB_IMAGE_BGRA: case GB_IMAGE_BGRX: goto __2103; case GB_IMAGE_ARGB: case GB_IMAGE_XRGB: goto __1230; case GB_IMAGE_RGB: goto __012X; case GB_IMAGE_BGR: goto __210X; } } __0123: memcpy(dst, src, w * h * 4); return; __3210: while (d < dm) { d[0] = s[3]; d[1] = s[2]; d[2] = s[1]; d[3] = s[0]; s += 4; d += 4; } return; __2103: while (d < dm) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; d[3] = s[3]; s += 4; d += 4; } return; __1230: while (d < dm) { d[0] = s[1]; d[1] = s[2]; d[2] = s[3]; d[3] = s[0]; s += 4; d += 4; } return; __012X: while (d < dm) { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; d[3] = 0xFF; s += 3; d += 4; } return; __210X: while (d < dm) { d[0] = s[2]; d[1] = s[1]; d[2] = s[0]; d[3] = 0xFF; s += 3; d += 4; } return; }