gambas-source-code/main/gbx/gbx_library.c
Benoît Minisini e945a9faa6 [INTERPRETER]
* NEW: Requesting a component interface automatically loads the component 
  now.
* NEW: The Image and Picture functions in the interpreter API were removed.

[GB.DRAW]
* NEW: A new function in the Draw interface to get the size of a picture.
  This function replaces the removed Picture interpreter API.

[GB.IMAGE]
* NEW: This is a new component that manages images in memory. It implements 
  the Image class, can create images of many formats (RGB, RGBA, BGRA...) 
  and convert image data between different formats. This component replaces
  the previous interpreter Image API. All components were ported to this
  new image management system by loading this component automatically.
  Beware that the Image constructor has changed! The transparent property
  has been removed, and there is an optional color argument that is used
  for initializing the image data. Moreover, many classes (Webcam, 
  PdfDocument...) that have an Image property lost their Picture property.
  Now to get a Picture, you must use the Image property and then convert
  the Image to a Picture.

[GB.QT]
* BUG: As now the Image class overrides the one located in gb.image, it 
  must be declared early, at least earlier than the Picture class.


git-svn-id: svn://localhost/gambas/trunk@1803 867c0c6c-44f3-4631-809d-bfa615b0a4ec
2009-01-16 23:12:10 +00:00

553 lines
10 KiB
C
Raw Blame History

/***************************************************************************
library.c
GAMBAS plug-in management routines
(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_LIBRARY_C
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_common_case.h"
#include "gb_error.h"
#include "gb_alloc.h"
#include "gb_replace.h"
#include "gb_magic.h"
#include <fcntl.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>
#include <ctype.h>
#include "gb_error.h"
#include "gbx_class.h"
#include "gbx_exec.h"
#include "gbx_event.h"
#include "gbx_stack.h"
#include "gb_file.h"
#include "gbx_archive.h"
#include "gbx_project.h"
#include "gbx_api.h"
#include "gbx_string.h"
#include "gbx_object.h"
#include "gbx_component.h"
#include "gbx_library.h"
/*#define DEBUG*/
//#define DEBUG_PRELOAD
// Maximum size of a project or startup file
// This avoids reading too much in the archive file!
#define MAX_SIZE 2048
int _bytes_read = 0;
#if 0
static lt_ptr library_malloc(size_t size)
{
lt_ptr ptr;
ALLOC(&ptr, size, "library_malloc");
printf("library_malloc: %d -> %p\n", size, ptr);
return ptr;
}
static void library_free(lt_ptr ptr)
{
printf("library_free -> %p\n", ptr);
FREE(&ptr, "library_free");
}
#endif
static void *get_symbol(LIBRARY *lib, const char *symbol, bool err)
{
void *sym;
sym = lt_dlsym(lib->handle, symbol);
if (sym == NULL && err)
{
strcpy(COMMON_buffer, lt_dlerror());
lt_dlclose(lib->handle);
lib->handle = NULL;
THROW(E_LIBRARY, lib->name, COMMON_buffer);
}
return sym;
}
static void copy_interface(intptr_t *src, intptr_t *dst)
{
for(;;)
{
if (*src == (intptr_t)0)
return;
*dst++ = *src++;
}
}
static bool read_line(FILE *fd, char *dir, int max)
{
char *p;
int c;
//ssize_t r;
p = dir;
for(;;)
{
_bytes_read++;
if (_bytes_read > MAX_SIZE)
return TRUE;
for (;;)
{
c = fgetc(fd); //read(fd, &c, 1);
if (c != EOF)
break;
if (errno != EINTR)
return TRUE;
}
if (c == '\n')
{
*p = 0;
return FALSE;
}
max--;
if (max > 0)
*p++ = c;
}
}
static void add_preload(char **env, const char *lib)
{
char *org;
if (*env == COMMON_buffer)
{
org = getenv("LD_PRELOAD");
if (org && *org)
*env += sprintf(*env, "%s ", org);
}
*env += sprintf(*env, "%s ", lib);
}
/*
static const char *start_with(const char *str, const char *begin)
{
int len = strlen(begin);
if (!strncasecmp(str, begin, len))
return &str[len];
else
return NULL;
}
*/
static bool check_preload(const char *lib, char **penv)
{
if (strcasecmp(lib, "gb.qt") == 0)
{
add_preload(penv, "libqt-mt.so.3");
#ifdef DEBUG_PRELOAD
fprintf(stderr, "found %s\n", lib);
#endif
return TRUE;
}
//#if HAVE_KDE_COMPONENT
else if (strcasecmp(lib, "gb.qt.kde") == 0)
{
/*add_preload(&env, libdir, p);*/
add_preload(penv, "libkdecore.so.4");
add_preload(penv, "libkdeui.so.4");
add_preload(penv, "libDCOP.so.4");
add_preload(penv, "libkio.so.4");
/*fprintf(stderr, "Warning: preloading KDE libraries\n");*/
#ifdef DEBUG_PRELOAD
fprintf(stderr, "found %s\n", lib);
#endif
return TRUE;
}
else
return FALSE;
}
void LIBRARY_preload(const char *file, char **argv)
{
#if DO_PRELOADING
const char *path;
char dir[MAX_PATH];
/*char libdir[MAX_PATH];*/
FILE *fd;
char *env;
bool preload;
char *err = NULL;
bool startup = FALSE;
env = getenv("GAMBAS_PRELOAD");
if (env)
{
#ifdef DEBUG_PRELOAD
fprintf(stderr, "Preloading done.\nLD_PRELOAD=%s\nGAMBAS_PRELOAD=%s\n", getenv("LD_PRELOAD"), getenv("GAMBAS_PRELOAD"));
#endif
if (*env)
setenv("LD_PRELOAD", env, TRUE);
else
unsetenv("LD_PRELOAD");
unsetenv("GAMBAS_PRELOAD");
return;
}
_bytes_read = 0;
preload = FALSE;
if (!EXEC_arch)
{
if (file == NULL)
file = ".";
if (*file == '/')
{
strcpy(dir, file);
}
else
{
if (*file == '.' && file[1] == '/')
file += 2;
path = FILE_getcwd(file);
if (path == NULL)
goto _PANIC;
chdir(path);
path = FILE_getcwd(NULL);
if (path == NULL)
goto _PANIC;
strcpy(dir, path);
}
file = FILE_cat(dir, ".startup", NULL);
/*if (!FILE_exist(file))
file = FILE_cat(dir, ".project", NULL);*/
}
fd = fopen(file, "r");
/* Silently ignored */
if (!fd)
return;
if (EXEC_arch)
fseek(fd, 32 + sizeof(ARCH_HEADER), SEEK_SET);
read_line(fd, dir, MAX_PATH);
env = COMMON_buffer;
//if (!start_with(dir, PROJECT_MAGIC))
//{
// We suppose that we have a .startup file.
startup = TRUE;
while (*dir)
read_line(fd, dir, MAX_PATH);
for(;;)
{
if (read_line(fd, dir, MAX_PATH))
break;
if (!*dir)
break;
preload |= check_preload(dir, &env);
}
/*
}
else
{
stop = FALSE;
for(;;)
{
if (read_line(fd, dir, MAX_PATH))
break;
if ((p = start_with(dir, "library=")) || (p = start_with(dir, "component=")))
{
preload |= check_preload(p, &env);
stop = TRUE;
}
else if (stop)
break;
}
}
*/
fclose(fd);
if (preload)
{
env = getenv("LD_PRELOAD");
if (env && *env)
setenv("GAMBAS_PRELOAD", env, TRUE);
else
setenv("GAMBAS_PRELOAD", "", TRUE);
setenv("LD_PRELOAD", COMMON_buffer, TRUE);
#ifdef DEBUG_PRELOAD
fprintf(stderr, "Preloading...\nLD_PRELOAD=%s\nGAMBAS_PRELOAD=%s\n", getenv("LD_PRELOAD"), getenv("GAMBAS_PRELOAD"));
#endif
execv(GAMBAS_LINK_PATH, argv);
}
return;
_PANIC:
fprintf(stderr, "Cannot preload libraries: %s\n", err ? err : strerror(errno));
#endif
}
void LIBRARY_init(void)
{
/*if (putenv("LD_BIND_NOW=true"))
ERROR_panic("Cannot set LD_BIND_NOW: &1", strerror(errno));
if (putenv("KDE_MALLOC=0"))
ERROR_panic("Cannot set KDE_MALLOC: &1", strerror(errno));*/
/*lt_dlmalloc = library_malloc;
lt_dlfree = library_free;*/
#ifndef DONT_USE_LTDL
if (lt_dlinit())
ERROR_panic("Cannot initialize plug-in management: %s", lt_dlerror());
#endif
}
void LIBRARY_exit(void)
{
#ifndef DONT_USE_LTDL
lt_dlexit();
#endif
}
void LIBRARY_get_interface(LIBRARY *lib, int version, void *iface)
{
char symbol[32];
int i, len;
char c;
len = strlen(lib->name);
for (i = 0; i < len; i++)
{
c = toupper(lib->name[i]);
if (!isalnum(c))
c = '_';
symbol[i] = c;
}
sprintf(&symbol[len], "_%d", version);
copy_interface((intptr_t *)get_symbol(lib, symbol, TRUE), (intptr_t *)iface);
}
boolean LIBRARY_get_interface_by_name(const char *name, int version, void *iface)
{
COMPONENT *comp;
comp = COMPONENT_find(name);
if (!comp || !comp->library)
return TRUE;
LIBRARY_get_interface(comp->library, version, iface);
return FALSE;
}
LIBRARY *LIBRARY_create(const char *name)
{
LIBRARY *lib;
ALLOC_ZERO(&lib, sizeof(LIBRARY), "LIBRARY_create");
lib->handle = NULL;
lib->name = name;
/*if (name)
{
lib->persistent = FALSE;
lib->preload = FALSE;
}
else
{
lib->persistent = TRUE;
lib->preload = TRUE;
}*/
return lib;
}
void LIBRARY_delete(LIBRARY *lib)
{
LIBRARY_unload(lib);
FREE(&lib, "LIBRARY_delete");
}
void LIBRARY_load(LIBRARY *lib)
{
int (*func)();
GB_INTERFACE *iface;
GB_DESC **desc;
char *path;
#ifdef DEBUG
clock_t t = clock();
fprintf(stderr, "Loading library %s\n", lib->name);
#endif
if (lib->handle)
return;
path = FILE_buffer();
sprintf(path, LIB_PATTERN, COMPONENT_path, lib->name);
if (!FILE_exist(path))
sprintf(path, LIB_PATTERN, COMPONENT_user_path, lib->name);
#ifndef DONT_USE_LTDL
/* no more available in libltld ?
lt_dlopen_flag = RTLD_LAZY;
*/
lib->handle = lt_dlopenext(path);
#else
lib->handle = dlopen(path, RTLD_LAZY);
#endif
if (lib->handle == NULL)
THROW(E_LIBRARY, path, lt_dlerror());
func = get_symbol(lib, LIB_INIT, TRUE);
/* Interface de Gambas */
iface = get_symbol(lib, LIB_GAMBAS, TRUE);
copy_interface((intptr_t *)(void *)GAMBAS_Api, (intptr_t *)(void *)iface);
/* Signal function */
lib->signal = (void(*)())get_symbol(lib, LIB_SIGNAL, FALSE);
lib->info = (int(*)())get_symbol(lib, LIB_INFO, FALSE);
/* Initialisation */
lib->persistent = (boolean)(*func)();
/* Déclaration des classes */
desc = get_symbol(lib, LIB_CLASS, FALSE);
if (desc)
LIBRARY_declare(desc);
#ifdef DEBUG
fprintf(stderr, "Library %s loaded ", lib->name);
fprintf(stderr, "in %g s\n", ((double)(clock() - t) / CLOCKS_PER_SEC));
#endif
}
void LIBRARY_declare(GB_DESC **desc)
{
GB_DESC **p;
p = desc;
while (*p != NULL)
{
CLASS_find_global((*p)->name);
p++;
}
p = desc;
while (*p != NULL)
{
if (CLASS_register(*p) == NULL)
THROW(E_REGISTER, (*p)->name);
p++;
}
}
void LIBRARY_unload(LIBRARY *lib)
{
void (*gambas_exit)();
if (lib->handle == NULL)
return;
/* Pas de lib<69>ation des classes pr<70>harg<72> ! */
/* V<>ification qu'aucune classe de la librairie n'est instanci<63> ! */
gambas_exit = lt_dlsym(lib->handle, LIB_EXIT);
if (gambas_exit != NULL)
(*gambas_exit)();
if (lib->persistent)
{
gambas_exit = lt_dlsym(lib->handle, "_fini");
if (gambas_exit != NULL)
(*gambas_exit)();
}
else
lt_dlclose(lib->handle);
lib->handle = NULL;
#ifdef DEBUG
printf("Unloading library %s\n", lib->name);
#endif
}