00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifdef HAVE_CONFIG_H
00018 #include "config.h"
00019 #endif
00020
00021 #include <string.h>
00022 #ifdef ENABLE_LTDL
00023 #include <ltdl.h>
00024 #endif
00025
00026 #include "memory.h"
00027 #include "types.h"
00028 #include "graph.h"
00029 #include "gvplugin.h"
00030 #include "gvcjob.h"
00031 #include "gvcint.h"
00032 #include "gvcproc.h"
00033
00034 extern const int Demand_Loading;
00035
00036
00037
00038
00039
00040
00041 #define ELEM(x) #x,
00042 static char *api_names[] = { APIS };
00043 #undef ELEM
00044
00045
00046 api_t gvplugin_api(char *str)
00047 {
00048 int api;
00049
00050 for (api = 0; api < ARRAY_SIZE(api_names); api++) {
00051 if (strcmp(str, api_names[api]) == 0)
00052 return (api_t)api;
00053 }
00054 return -1;
00055 }
00056
00057
00058 char *gvplugin_api_name(api_t api)
00059 {
00060 if (api < 0 || api >= ARRAY_SIZE(api_names))
00061 return NULL;
00062 return api_names[api];
00063 }
00064
00065
00066
00067
00068
00069
00070 boolean gvplugin_install(GVC_t * gvc, api_t api,
00071 char *typestr, int quality, char *packagename, char *path,
00072 gvplugin_installed_t * typeptr)
00073 {
00074 gvplugin_available_t *plugin, **pnext;
00075 #define TYPSIZ 63
00076 char *p, pins[TYPSIZ+1], pnxt[TYPSIZ+1];
00077
00078 if (api < 0)
00079 return FALSE;
00080
00081 strncpy(pins, typestr, TYPSIZ);
00082 if ((p = strchr(pins, ':')))
00083 *p = '\0';
00084
00085
00086 pnext = &(gvc->apis[api]);
00087
00088
00089 while (*pnext) {
00090 strncpy(pnxt, (*pnext)->typestr, TYPSIZ);
00091 if ((p = strchr(pnxt, ':')))
00092 *p = '\0';
00093 if (strcmp(pins, pnxt) <= 0)
00094 break;
00095 pnext = &((*pnext)->next);
00096 }
00097
00098
00099 while (*pnext) {
00100 strncpy(pnxt, (*pnext)->typestr, TYPSIZ);
00101 if ((p = strchr(pnxt, ':')))
00102 *p = '\0';
00103 if (strcmp(pins, pnxt) != 0)
00104 break;
00105 if (quality >= (*pnext)->quality)
00106 break;
00107 pnext = &((*pnext)->next);
00108 }
00109
00110 plugin = GNEW(gvplugin_available_t);
00111 plugin->next = *pnext;
00112 *pnext = plugin;
00113 plugin->typestr = typestr;
00114 plugin->quality = quality;
00115 plugin->packagename = packagename;
00116 plugin->path = path;
00117 plugin->typeptr = typeptr;
00118
00119 return TRUE;
00120 }
00121
00122
00123
00124
00125
00126
00127
00128
00129 static boolean gvplugin_activate(GVC_t * gvc, api_t api,
00130 char *typestr, char *packagename, char *path,
00131 gvplugin_installed_t * typeptr)
00132 {
00133 gvplugin_available_t **pnext;
00134
00135
00136 if (api < 0)
00137 return FALSE;
00138
00139
00140 pnext = &(gvc->apis[api]);
00141
00142 while (*pnext) {
00143 if ( (strcasecmp(typestr, (*pnext)->typestr) == 0)
00144 && (strcasecmp(packagename, (*pnext)->packagename) == 0)
00145 && (strcasecmp(path, (*pnext)->path) == 0)) {
00146 (*pnext)->typeptr = typeptr;
00147 return TRUE;
00148 }
00149 pnext = &((*pnext)->next);
00150 }
00151 return FALSE;
00152 }
00153
00154 gvplugin_library_t *gvplugin_library_load(GVC_t *gvc, char *path)
00155 {
00156 #ifdef ENABLE_LTDL
00157 lt_dlhandle hndl;
00158 lt_ptr ptr;
00159 char *s, *sym;
00160 int len;
00161 static char *p;
00162 static int lenp;
00163 char *libdir;
00164 char *suffix = "_LTX_library";
00165
00166 if (!Demand_Loading)
00167 return NULL;
00168
00169 libdir = gvconfig_libdir();
00170 len = strlen(libdir) + 1 + strlen(path) + 1;
00171 if (len > lenp) {
00172 lenp = len+20;
00173 if (p)
00174 p = grealloc(p, lenp);
00175 else
00176 p = gmalloc(lenp);
00177 }
00178
00179 #ifdef WIN32
00180 if (path[1] == ':') {
00181 #else
00182 if (path[0] == '/') {
00183 #endif
00184 strcpy(p, path);
00185 } else {
00186 strcpy(p, libdir);
00187 strcat(p, DIRSEP);
00188 strcat(p, path);
00189 }
00190
00191 if (lt_dlinit()) {
00192 agerr(AGERR, "failed to init libltdl\n");
00193 return NULL;
00194 }
00195 hndl = lt_dlopen (p);
00196 if (!hndl) {
00197 agerr(AGWARN, "Could not load \"%s\" - %s\n", p, (char*)lt_dlerror());
00198 return NULL;
00199 }
00200 if (gvc->common.verbose >= 2)
00201 fprintf(stderr, "Loading %s\n", p);
00202
00203 s = strrchr(p, DIRSEP[0]);
00204 len = strlen(s);
00205 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
00206 if (len < strlen("/gvplugin_x")) {
00207 #else
00208 if (len < strlen("/libgvplugin_x")) {
00209 #endif
00210 agerr (AGERR,"invalid plugin path \"%s\"\n", p);
00211 return NULL;
00212 }
00213 sym = gmalloc(len + strlen(suffix) + 1);
00214 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
00215 strcpy(sym, s+1);
00216 #else
00217 strcpy(sym, s+4);
00218 #endif
00219 #if defined(__CYGWIN__) || defined(__MINGW32__)
00220 s = strchr(sym, '-');
00221 #else
00222 s = strchr(sym, '.');
00223 #endif
00224 strcpy(s,suffix);
00225
00226 ptr = lt_dlsym (hndl, sym);
00227 if (!ptr) {
00228 agerr (AGERR,"failed to resolve %s in %s\n", sym, p);
00229 free(sym);
00230 return NULL;
00231 }
00232 free(sym);
00233 return (gvplugin_library_t *)(ptr);
00234 #else
00235 agerr (AGERR,"dynamic loading not available\n");
00236 return NULL;
00237 #endif
00238 }
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 gvplugin_available_t *gvplugin_load(GVC_t * gvc, api_t api, char *str)
00254 {
00255 gvplugin_available_t **pnext, *rv;
00256 gvplugin_library_t *library;
00257 gvplugin_api_t *apis;
00258 gvplugin_installed_t *types;
00259 #define TYPBUFSIZ 64
00260 char reqtyp[TYPBUFSIZ], typ[TYPBUFSIZ];
00261 char *reqdep, *dep = NULL, *reqpkg;
00262 int i;
00263 api_t apidep;
00264
00265
00266 if (api < 0)
00267 return NULL;
00268
00269 if (api == API_device
00270 || api == API_loadimage)
00271
00272 apidep = API_render;
00273 else
00274 apidep = api;
00275
00276 strncpy(reqtyp, str, TYPBUFSIZ-1);
00277 reqdep = strchr(reqtyp, ':');
00278 if (reqdep) {
00279 *reqdep++ = '\0';
00280 reqpkg = strchr(reqdep, ':');
00281 if (reqpkg)
00282 *reqpkg++ = '\0';
00283 }
00284 else
00285 reqpkg = NULL;
00286
00287
00288 for (pnext = &(gvc->apis[api]); *pnext; pnext = &((*pnext)->next)) {
00289 strncpy(typ, (*pnext)->typestr, TYPBUFSIZ-1);
00290 dep = strchr(typ, ':');
00291 if (dep)
00292 *dep++ = '\0';
00293 if (strcmp(typ, reqtyp))
00294 continue;
00295 if (dep && reqdep && strcmp(dep, reqdep))
00296 continue;
00297 if (! reqpkg)
00298 break;
00299 if (strcmp(reqpkg, (*pnext)->packagename) == 0)
00300 break;
00301 }
00302 rv = *pnext;
00303
00304 if (dep && (apidep != api))
00305 if (! (gvplugin_load(gvc, apidep, dep)))
00306 rv = NULL;
00307
00308 if (rv && rv->typeptr == NULL) {
00309 library = gvplugin_library_load(gvc, rv->path);
00310 if (library) {
00311
00312
00313 for (apis = library->apis; (types = apis->types); apis++) {
00314 for (i = 0; types[i].type; i++) {
00315
00316
00317 gvplugin_activate(gvc,
00318 apis->api,
00319 types[i].type,
00320 library->packagename,
00321 rv->path,
00322 &types[i]);
00323 }
00324 }
00325 if (gvc->common.verbose >= 1)
00326 fprintf(stderr, "Activated plugin library: %s\n",
00327 rv->path ? rv->path : "<builtin>");
00328 }
00329 }
00330
00331
00332 if (rv && rv->typeptr == NULL)
00333 rv = NULL;
00334
00335 if (rv && gvc->common.verbose >= 1)
00336 fprintf(stderr, "Using %s: %s:%s\n",
00337 api_names[api],
00338 rv->typestr,
00339 rv->packagename
00340 );
00341
00342 gvc->api[api] = rv;
00343 return rv;
00344 }
00345
00346
00347
00348 static const char *append_buf(char sep, char *str, boolean new)
00349 {
00350 static char *buf;
00351 static int bufsz, pos;
00352 int len;
00353 char *p;
00354
00355 if (new)
00356 pos = 0;
00357 len = strlen(str) + 1;
00358 if (bufsz < (pos + len + 1)) {
00359 bufsz += 4 * len;
00360 buf = grealloc(buf, bufsz);
00361 }
00362 p = buf + pos;
00363 *p++ = sep;
00364 strcpy(p, str);
00365 pos += len;
00366 return buf;
00367 }
00368
00369
00370 const char *gvplugin_list(GVC_t * gvc, api_t api, char *str)
00371 {
00372 gvplugin_available_t **pnext, **plugin;
00373 const char *buf = NULL;
00374 char *s, *p, *q, *typestr_last;
00375 boolean new = TRUE;
00376
00377
00378 if (api < 0)
00379 return NULL;
00380
00381
00382 s = strdup(str);
00383 p = strchr(s, ':');
00384 if (p)
00385 *p++ = '\0';
00386
00387
00388 plugin = &(gvc->apis[api]);
00389
00390 if (p) {
00391
00392 for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) {
00393 q = strdup((*pnext)->typestr);
00394 if ((p = strchr(q, ':')))
00395 *p++ = '\0';
00396
00397 if (!s[0] || strcasecmp(s, q) == 0) {
00398
00399 append_buf(' ', (*pnext)->typestr, new);
00400 buf = append_buf(':', (*pnext)->packagename, FALSE);
00401 new = FALSE;
00402 }
00403 free(q);
00404 }
00405 }
00406 free(s);
00407 if (new) {
00408
00409 typestr_last = NULL;
00410 for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) {
00411
00412 q = strdup((*pnext)->typestr);
00413 if ((p = strchr(q, ':')))
00414 *p++ = '\0';
00415 if (!typestr_last || strcasecmp(typestr_last, q) != 0) {
00416
00417 buf = append_buf(' ', q, new);
00418 new = FALSE;
00419 }
00420 if(!typestr_last)
00421 free(typestr_last);
00422 typestr_last = q;
00423 }
00424 if(!typestr_last)
00425 free(typestr_last);
00426 }
00427 if (!buf)
00428 buf = "";
00429 return buf;
00430 }
00431
00432 void gvplugin_write_status(GVC_t * gvc)
00433 {
00434 int api;
00435
00436 #ifdef ENABLE_LTDL
00437 if (Demand_Loading) {
00438 fprintf(stderr,"The plugin configuration file:\n\t%s\n", gvc->config_path);
00439 if (gvc->config_found)
00440 fprintf(stderr,"\t\twas successfully loaded.\n");
00441 else
00442 fprintf(stderr,"\t\twas not found or not usable. No on-demand plugins.\n");
00443 }
00444 else {
00445 fprintf(stderr,"Demand loading of plugins is disabled.\n");
00446 }
00447 #endif
00448
00449 for (api = 0; api < ARRAY_SIZE(api_names); api++) {
00450 if (gvc->common.verbose >= 2)
00451 fprintf(stderr," %s\t: %s\n", api_names[api], gvplugin_list(gvc, api, ":"));
00452 else
00453 fprintf(stderr," %s\t: %s\n", api_names[api], gvplugin_list(gvc, api, "?"));
00454 }
00455
00456 }