|
Graphviz
2.29.20120524.0446
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 #ifdef HAVE_CONFIG_H 00015 #include "config.h" 00016 #endif 00017 00018 #include <string.h> 00019 #ifdef ENABLE_LTDL 00020 #include <ltdl.h> 00021 #endif 00022 00023 #include <agxbuf.h> 00024 #include "memory.h" 00025 #include "types.h" 00026 #include "gvplugin.h" 00027 #include "gvcjob.h" 00028 #include "gvcint.h" 00029 #include "gvcproc.h" 00030 #include "gvio.h" 00031 00032 #include "const.h" 00033 00034 #ifndef HAVE_STRCASECMP 00035 extern int strcasecmp(const char *s1, const char *s2); 00036 #endif 00037 00038 /* 00039 * Define an apis array of name strings using an enumerated api_t as index. 00040 * The enumerated type is defined gvplugin.h. The apis array is 00041 * inititialized here by redefining ELEM and reinvoking APIS. 00042 */ 00043 #define ELEM(x) #x, 00044 static char *api_names[] = { APIS }; /* "render", "layout", ... */ 00045 #undef ELEM 00046 00047 /* translate a string api name to its type, or -1 on error */ 00048 api_t gvplugin_api(char *str) 00049 { 00050 int api; 00051 00052 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00053 if (strcmp(str, api_names[api]) == 0) 00054 return (api_t)api; 00055 } 00056 return -1; /* invalid api */ 00057 } 00058 00059 /* translate api_t into string name, or NULL */ 00060 char *gvplugin_api_name(api_t api) 00061 { 00062 if (api < 0 || api >= ARRAY_SIZE(api_names)) 00063 return NULL; 00064 return api_names[api]; 00065 } 00066 00067 /* install a plugin description into the list of available plugins 00068 * list is alpha sorted by type (not including :dependency), then 00069 * quality sorted within the type, then, if qualities are the same, 00070 * last install wins. 00071 */ 00072 boolean gvplugin_install(GVC_t * gvc, api_t api, const char *typestr, 00073 int quality, gvplugin_package_t *package, 00074 gvplugin_installed_t * typeptr) 00075 { 00076 gvplugin_available_t *plugin, **pnext; 00077 #define TYPSIZ 63 00078 char *p, pins[TYPSIZ+1], pnxt[TYPSIZ+1]; 00079 00080 if (api < 0) 00081 return FALSE; 00082 00083 strncpy(pins, typestr, TYPSIZ); 00084 if ((p = strchr(pins, ':'))) 00085 *p = '\0'; 00086 00087 /* point to the beginning of the linked list of plugins for this api */ 00088 pnext = &(gvc->apis[api]); 00089 00090 /* keep alpha-sorted and insert new duplicates ahead of old */ 00091 while (*pnext) { 00092 strncpy(pnxt, (*pnext)->typestr, TYPSIZ); 00093 if ((p = strchr(pnxt, ':'))) 00094 *p = '\0'; 00095 if (strcmp(pins, pnxt) <= 0) 00096 break; 00097 pnext = &((*pnext)->next); 00098 } 00099 00100 /* keep quality sorted within type and insert new duplicates ahead of old */ 00101 while (*pnext) { 00102 strncpy(pnxt, (*pnext)->typestr, TYPSIZ); 00103 if ((p = strchr(pnxt, ':'))) 00104 *p = '\0'; 00105 if (strcmp(pins, pnxt) != 0) 00106 break; 00107 if (quality >= (*pnext)->quality) 00108 break; 00109 pnext = &((*pnext)->next); 00110 } 00111 00112 plugin = GNEW(gvplugin_available_t); 00113 plugin->next = *pnext; 00114 *pnext = plugin; 00115 plugin->typestr = typestr; 00116 plugin->quality = quality; 00117 plugin->package = package; 00118 plugin->typeptr = typeptr; /* null if not loaded */ 00119 00120 return TRUE; 00121 } 00122 00123 /* Activate a plugin description in the list of available plugins. 00124 * This is used when a plugin-library loaded because of demand for 00125 * one of its plugins. It updates the available plugin data with 00126 * pointers into the loaded library. 00127 * NB the quality value is not replaced as it might have been 00128 * manually changed in the config file. 00129 */ 00130 static boolean gvplugin_activate(GVC_t * gvc, api_t api, 00131 const char *typestr, char *name, char *path, 00132 gvplugin_installed_t * typeptr) 00133 { 00134 gvplugin_available_t **pnext; 00135 00136 00137 if (api < 0) 00138 return FALSE; 00139 00140 /* point to the beginning of the linked list of plugins for this api */ 00141 pnext = &(gvc->apis[api]); 00142 00143 while (*pnext) { 00144 if ( (strcasecmp(typestr, (*pnext)->typestr) == 0) 00145 && (strcasecmp(name, (*pnext)->package->name) == 0) 00146 && ((*pnext)->package->path != 0) 00147 && (strcasecmp(path, (*pnext)->package->path) == 0)) { 00148 (*pnext)->typeptr = typeptr; 00149 return TRUE; 00150 } 00151 pnext = &((*pnext)->next); 00152 } 00153 return FALSE; 00154 } 00155 00156 gvplugin_library_t *gvplugin_library_load(GVC_t *gvc, char *path) 00157 { 00158 #ifdef ENABLE_LTDL 00159 lt_dlhandle hndl; 00160 lt_ptr ptr; 00161 char *s, *sym; 00162 int len; 00163 static char *p; 00164 static int lenp; 00165 char *libdir; 00166 char *suffix = "_LTX_library"; 00167 00168 if (! gvc->common.demand_loading) 00169 return NULL; 00170 00171 libdir = gvconfig_libdir(gvc); 00172 len = strlen(libdir) + 1 + strlen(path) + 1; 00173 if (len > lenp) { 00174 lenp = len+20; 00175 if (p) 00176 p = grealloc(p, lenp); 00177 else 00178 p = gmalloc(lenp); 00179 } 00180 00181 #ifdef WIN32 00182 if (path[1] == ':') { 00183 #else 00184 if (path[0] == '/') { 00185 #endif 00186 strcpy(p, path); 00187 } else { 00188 strcpy(p, libdir); 00189 strcat(p, DIRSEP); 00190 strcat(p, path); 00191 } 00192 00193 if (lt_dlinit()) { 00194 agerr(AGERR, "failed to init libltdl\n"); 00195 return NULL; 00196 } 00197 hndl = lt_dlopen (p); 00198 if (!hndl) { 00199 agerr(AGWARN, "Could not load \"%s\" - %s\n", p, (char*)lt_dlerror()); 00200 return NULL; 00201 } 00202 if (gvc->common.verbose >= 2) 00203 fprintf(stderr, "Loading %s\n", p); 00204 00205 s = strrchr(p, DIRSEP[0]); 00206 len = strlen(s); 00207 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) 00208 if (len < strlen("/gvplugin_x")) { 00209 #else 00210 if (len < strlen("/libgvplugin_x")) { 00211 #endif 00212 agerr (AGERR,"invalid plugin path \"%s\"\n", p); 00213 return NULL; 00214 } 00215 sym = gmalloc(len + strlen(suffix) + 1); 00216 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) 00217 strcpy(sym, s+1); /* strip leading "/" */ 00218 #else 00219 strcpy(sym, s+4); /* strip leading "/lib" or "/cyg" */ 00220 #endif 00221 #if defined(__CYGWIN__) || defined(__MINGW32__) 00222 s = strchr(sym, '-'); /* strip trailing "-1.dll" */ 00223 #else 00224 s = strchr(sym, '.'); /* strip trailing ".so.0" or ".dll" or ".sl" */ 00225 #endif 00226 strcpy(s,suffix); /* append "_LTX_library" */ 00227 00228 ptr = lt_dlsym (hndl, sym); 00229 if (!ptr) { 00230 agerr (AGERR,"failed to resolve %s in %s\n", sym, p); 00231 free(sym); 00232 return NULL; 00233 } 00234 free(sym); 00235 return (gvplugin_library_t *)(ptr); 00236 #else 00237 agerr (AGERR,"dynamic loading not available\n"); 00238 return NULL; 00239 #endif 00240 } 00241 00242 00243 /* load a plugin of type=str 00244 the str can optionally contain one or more ":dependencies" 00245 00246 examples: 00247 png 00248 png:cairo 00249 fully qualified: 00250 png:cairo:cairo 00251 png:cairo:gd 00252 png:gd:gd 00253 00254 */ 00255 gvplugin_available_t *gvplugin_load(GVC_t * gvc, api_t api, const char *str) 00256 { 00257 gvplugin_available_t **pnext, *rv; 00258 gvplugin_library_t *library; 00259 gvplugin_api_t *apis; 00260 gvplugin_installed_t *types; 00261 #define TYPBUFSIZ 64 00262 char reqtyp[TYPBUFSIZ], typ[TYPBUFSIZ]; 00263 char *reqdep, *dep = NULL, *reqpkg; 00264 int i; 00265 api_t apidep; 00266 00267 /* check for valid apis[] index */ 00268 if (api < 0) 00269 return NULL; 00270 00271 if (api == API_device 00272 || api == API_loadimage) /* api dependencies - FIXME - find better way to code these *s */ 00273 00274 apidep = API_render; 00275 else 00276 apidep = api; 00277 00278 strncpy(reqtyp, str, TYPBUFSIZ-1); 00279 reqdep = strchr(reqtyp, ':'); 00280 if (reqdep) { 00281 *reqdep++ = '\0'; 00282 reqpkg = strchr(reqdep, ':'); 00283 if (reqpkg) 00284 *reqpkg++ = '\0'; 00285 } 00286 else 00287 reqpkg = NULL; 00288 00289 /* iterate the linked list of plugins for this api */ 00290 for (pnext = &(gvc->apis[api]); *pnext; pnext = &((*pnext)->next)) { 00291 strncpy(typ, (*pnext)->typestr, TYPBUFSIZ-1); 00292 dep = strchr(typ, ':'); 00293 if (dep) 00294 *dep++ = '\0'; 00295 if (strcmp(typ, reqtyp)) 00296 continue; /* types empty or mismatched */ 00297 if (dep && reqdep && strcmp(dep, reqdep)) 00298 continue; /* dependencies not empty, but mismatched */ 00299 if (! reqpkg || strcmp(reqpkg, (*pnext)->package->name) == 0) 00300 { 00301 /* found with no packagename constraints, or with required matching packagname */ 00302 00303 if (dep && (apidep != api)) /* load dependency if needed, continue if can't find */ 00304 if (! (gvplugin_load(gvc, apidep, dep))) 00305 continue; 00306 break; 00307 } 00308 } 00309 rv = *pnext; 00310 00311 if (rv && rv->typeptr == NULL) { 00312 library = gvplugin_library_load(gvc, rv->package->path); 00313 if (library) { 00314 00315 /* Now activate the library with real type ptrs */ 00316 for (apis = library->apis; (types = apis->types); apis++) { 00317 for (i = 0; types[i].type; i++) { 00318 /* NB. quality is not checked or replaced 00319 * in case user has manually edited quality in config */ 00320 gvplugin_activate(gvc, 00321 apis->api, 00322 types[i].type, 00323 library->packagename, 00324 rv->package->path, 00325 &types[i]); 00326 } 00327 } 00328 if (gvc->common.verbose >= 1) 00329 fprintf(stderr, "Activated plugin library: %s\n", 00330 rv->package->path ? rv->package->path : "<builtin>"); 00331 } 00332 } 00333 00334 /* one last check for successfull load */ 00335 if (rv && rv->typeptr == NULL) 00336 rv = NULL; 00337 00338 if (rv && gvc->common.verbose >= 1) 00339 fprintf(stderr, "Using %s: %s:%s\n", 00340 api_names[api], 00341 rv->typestr, 00342 rv->package->name 00343 ); 00344 00345 gvc->api[api] = rv; 00346 return rv; 00347 } 00348 00349 /* assemble a string list of available plugins 00350 * non-re-entrant as character store is shared 00351 */ 00352 char *gvplugin_list(GVC_t * gvc, api_t api, const char *str) 00353 { 00354 static int first = 1; 00355 gvplugin_available_t **pnext, **plugin; 00356 char *bp; 00357 char *s, *p, *q, *typestr_last; 00358 boolean new = TRUE; 00359 static agxbuf xb; 00360 00361 /* check for valid apis[] index */ 00362 if (api < 0) 00363 return NULL; 00364 00365 /* check for valid str */ 00366 if (! str) 00367 return NULL; 00368 00369 if (first) { 00370 agxbinit(&xb, 0, 0); 00371 first = 0; 00372 } 00373 00374 /* does str have a :path modifier? */ 00375 #ifdef WIN32 00376 s = _strdup(str); 00377 #else 00378 s = strdup(str); 00379 #endif 00380 p = strchr(s, ':'); 00381 if (p) 00382 *p++ = '\0'; 00383 00384 /* point to the beginning of the linked list of plugins for this api */ 00385 plugin = &(gvc->apis[api]); 00386 00387 if (p) { /* if str contains a ':', and if we find a match for the type, 00388 then just list the alternative paths for the plugin */ 00389 for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) { 00390 q = strdup((*pnext)->typestr); 00391 if ((p = strchr(q, ':'))) 00392 *p++ = '\0'; 00393 /* list only the matching type, or all types if s is an empty string */ 00394 if (!s[0] || strcasecmp(s, q) == 0) { 00395 /* list each member of the matching type as "type:path" */ 00396 agxbputc(&xb,' '); agxbput(&xb, (*pnext)->typestr); 00397 agxbputc(&xb,':'); agxbput(&xb, (*pnext)->package->name); 00398 new = FALSE; 00399 } 00400 free(q); 00401 } 00402 } 00403 free(s); 00404 if (new) { /* if the type was not found, or if str without ':', 00405 then just list available types */ 00406 typestr_last = NULL; 00407 for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) { 00408 /* list only one instance of type */ 00409 q = strdup((*pnext)->typestr); 00410 if ((p = strchr(q, ':'))) 00411 *p++ = '\0'; 00412 if (!typestr_last || strcasecmp(typestr_last, q) != 0) { 00413 /* list it as "type" i.e. w/o ":path" */ 00414 agxbputc(&xb,' '); agxbput(&xb, q); 00415 new = FALSE; 00416 } 00417 if(!typestr_last) 00418 free(typestr_last); 00419 typestr_last = q; 00420 } 00421 if(!typestr_last) 00422 free(typestr_last); 00423 } 00424 if (new) 00425 bp = ""; 00426 else 00427 bp = agxbuse(&xb); 00428 return bp; 00429 } 00430 00431 /* gvPluginList: 00432 * Return list of plugins of type kind. 00433 * The size of the list is stored in sz. 00434 * The caller is responsible for freeing the storage. This involves 00435 * freeing each item, then the list. 00436 * Returns NULL on error, or if there are no plugins. 00437 * In the former case, sz is unchanged; in the latter, sz = 0. 00438 * 00439 * At present, the str argument is unused, but may be used to modify 00440 * the search as in gvplugin_list above. 00441 */ 00442 char **gvPluginList(GVC_t * gvc, char* kind, int* sz, const char *str) 00443 { 00444 int api; 00445 gvplugin_available_t **pnext, **plugin; 00446 int cnt = 0; 00447 char** list = NULL; 00448 char *p, *q, *typestr_last; 00449 00450 if (!kind) return NULL; 00451 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00452 if (!strcasecmp(kind,api_names[api])) 00453 break; 00454 } 00455 if (api == ARRAY_SIZE(api_names)) { 00456 agerr(AGERR, "unrecognized api name \"%s\"\n", kind); 00457 return NULL; 00458 } 00459 00460 /* point to the beginning of the linked list of plugins for this api */ 00461 plugin = &(gvc->apis[api]); 00462 typestr_last = NULL; 00463 for (pnext = plugin; *pnext; pnext = &((*pnext)->next)) { 00464 /* list only one instance of type */ 00465 q = strdup((*pnext)->typestr); 00466 if ((p = strchr(q, ':'))) 00467 *p++ = '\0'; 00468 if (!typestr_last || strcasecmp(typestr_last, q) != 0) { 00469 list = RALLOC(cnt+1,list,char*); 00470 list[cnt++] = q; 00471 } 00472 typestr_last = q; 00473 } 00474 00475 *sz = cnt; 00476 return list; 00477 } 00478 00479 void gvplugin_write_status(GVC_t * gvc) 00480 { 00481 int api; 00482 00483 #ifdef ENABLE_LTDL 00484 if (gvc->common.demand_loading) { 00485 fprintf(stderr,"The plugin configuration file:\n\t%s\n", gvc->config_path); 00486 if (gvc->config_found) 00487 fprintf(stderr,"\t\twas successfully loaded.\n"); 00488 else 00489 fprintf(stderr,"\t\twas not found or not usable. No on-demand plugins.\n"); 00490 } 00491 else { 00492 fprintf(stderr,"Demand loading of plugins is disabled.\n"); 00493 } 00494 #endif 00495 00496 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00497 if (gvc->common.verbose >= 2) 00498 fprintf(stderr," %s\t: %s\n", api_names[api], gvplugin_list(gvc, api, ":")); 00499 else 00500 fprintf(stderr," %s\t: %s\n", api_names[api], gvplugin_list(gvc, api, "?")); 00501 } 00502 00503 } 00504 00505 Agraph_t * gvplugin_graph(GVC_t * gvc) 00506 { 00507 Agraph_t *g, *sg, *ssg; 00508 Agnode_t *n, *m; 00509 Agedge_t *e; 00510 Agsym_t *a; 00511 gvplugin_package_t *package; 00512 gvplugin_available_t **pnext; 00513 char bufa[100], *buf1, *buf2, bufb[100], *p, *q, *t; 00514 int api, found; 00515 00516 #ifndef WITH_CGRAPH 00517 aginit(); 00518 agsetiodisc(NULL, gvfwrite, gvferror); 00519 /* set persistent attributes here */ 00520 agraphattr(NULL, "label", ""); 00521 agraphattr(NULL, "rankdir", ""); 00522 agraphattr(NULL, "rank", ""); 00523 agraphattr(NULL, "ranksep", ""); 00524 agnodeattr(NULL, "label", NODENAME_ESC); 00525 00526 g = agopen("G", AGDIGRAPH); 00527 #else 00528 g = agopen("G", Agdirected, NIL(Agdisc_t *)); 00529 agattr(g, AGRAPH, "label", ""); 00530 agattr(g, AGRAPH, "rankdir", ""); 00531 agattr(g, AGRAPH, "rank", ""); 00532 agattr(g, AGRAPH, "ranksep", ""); 00533 agattr(g, AGNODE, "label", NODENAME_ESC); 00534 #endif 00535 00536 a = agfindgraphattr(g, "rankdir"); 00537 #ifndef WITH_CGRAPH 00538 agxset(g, a->index, "LR"); 00539 #else 00540 agxset(g, a, "LR"); 00541 #endif 00542 00543 a = agfindgraphattr(g, "ranksep"); 00544 #ifndef WITH_CGRAPH 00545 agxset(g, a->index, "1.5"); 00546 #else 00547 agxset(g, a, "1.5"); 00548 #endif 00549 00550 a = agfindgraphattr(g, "label"); 00551 #ifndef WITH_CGRAPH 00552 agxset(g, a->index, "Plugins"); 00553 #else 00554 agxset(g, a, "Plugins"); 00555 #endif 00556 00557 for (package = gvc->packages; package; package = package->next) { 00558 strcpy(bufa, "cluster_"); 00559 strcat(bufa, package->name); 00560 #ifndef WITH_CGRAPH 00561 sg = agsubg(g, bufa); 00562 #else 00563 sg = agsubg(g, bufa, 1); 00564 #endif 00565 a = agfindgraphattr(sg, "label"); 00566 #ifndef WITH_CGRAPH 00567 agxset(sg, a->index, package->name); 00568 #else 00569 agxset(sg, a, package->name); 00570 #endif 00571 strcpy(bufa, package->name); 00572 strcat(bufa, "_"); 00573 buf1 = bufa + strlen(bufa); 00574 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00575 found = 0; 00576 strcpy(buf1, api_names[api]); 00577 #ifndef WITH_CGRAPH 00578 ssg = agsubg(sg, bufa); 00579 #else 00580 ssg = agsubg(sg, bufa, 1); 00581 #endif 00582 a = agfindgraphattr(ssg, "rank"); 00583 #ifndef WITH_CGRAPH 00584 agxset(ssg, a->index, "same"); 00585 #else 00586 agxset(ssg, a, "same"); 00587 #endif 00588 strcat(buf1, "_"); 00589 buf2 = bufa + strlen(bufa); 00590 for (pnext = &(gvc->apis[api]); *pnext; pnext = &((*pnext)->next)) { 00591 if ((*pnext)->package == package) { 00592 found++; 00593 t = q = strdup((*pnext)->typestr); 00594 if ((p = strchr(q, ':'))) *p++ = '\0'; 00595 /* Now p = renderer, e.g. "gd" 00596 * and q = device, e.g. "png" 00597 * or q = imageloader, e.g. "png" */ 00598 switch (api) { 00599 case API_device: 00600 case API_loadimage: 00601 00602 /* hack for aliases */ 00603 if (!strncmp(q,"jp",2)) 00604 q = "jpeg/jpe/jpg"; 00605 else if (!strncmp(q,"tif",3)) 00606 q = "tiff/tif"; 00607 else if (!strcmp(q,"x11") || !strcmp(q,"xlib")) 00608 q = "x11/xlib"; 00609 else if (!strcmp(q,"dot") || !strcmp(q,"gv")) 00610 q = "gv/dot"; 00611 00612 strcpy(buf2, q); 00613 #ifndef WITH_CGRAPH 00614 n = agnode(ssg, bufa); 00615 #else 00616 n = agnode(ssg, bufa, 1); 00617 #endif 00618 a = agfindnodeattr(g, "label"); 00619 #ifndef WITH_CGRAPH 00620 agxset(n, a->index, q); 00621 #else 00622 agxset(n, a, q); 00623 #endif 00624 if (! (p && *p)) { 00625 strcpy(bufb, "render_cg"); 00626 m = agfindnode(sg, bufb); 00627 if (!m) { 00628 #ifndef WITH_CGRAPH 00629 m = agnode(sg, bufb); 00630 #else 00631 m = agnode(sg, bufb, 1); 00632 #endif 00633 a = agfindgraphattr(g, "label"); 00634 #ifndef WITH_CGRAPH 00635 agxset(m, a->index, "cg"); 00636 #else 00637 agxset(m, a, "cg"); 00638 #endif 00639 } 00640 #ifndef WITH_CGRAPH 00641 agedge(sg, m, n); 00642 #else 00643 agedge(sg, m, n, NULL, 1); 00644 #endif 00645 } 00646 break; 00647 case API_render: 00648 strcpy(bufb, api_names[api]); 00649 strcat(bufb, "_"); 00650 strcat(bufb, q); 00651 #ifndef WITH_CGRAPH 00652 n = agnode(ssg, bufb); 00653 #else 00654 n = agnode(ssg, bufb, 1); 00655 #endif 00656 a = agfindnodeattr(g, "label"); 00657 #ifndef WITH_CGRAPH 00658 agxset(n, a->index, q); 00659 #else 00660 agxset(n, a, q); 00661 #endif 00662 break; 00663 default: 00664 break; 00665 } 00666 free(t); 00667 } 00668 } 00669 if (!found) 00670 #ifndef WITH_CGRAPH 00671 agdelete(ssg->meta_node->graph, ssg->meta_node); 00672 #else 00673 agdelete(g, ssg); 00674 #endif 00675 } 00676 } 00677 00678 #ifndef WITH_CGRAPH 00679 ssg = agsubg(g, "output_formats"); 00680 #else 00681 ssg = agsubg(g, "output_formats", 1); 00682 #endif 00683 a = agfindgraphattr(ssg, "rank"); 00684 #ifndef WITH_CGRAPH 00685 agxset(ssg, a->index, "same"); 00686 #else 00687 agxset(ssg, a, "same"); 00688 #endif 00689 for (package = gvc->packages; package; package = package->next) { 00690 strcpy(bufa, package->name); 00691 strcat(bufa, "_"); 00692 buf1 = bufa + strlen(bufa); 00693 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00694 strcpy(buf1, api_names[api]); 00695 strcat(buf1, "_"); 00696 buf2 = bufa + strlen(bufa); 00697 for (pnext = &(gvc->apis[api]); *pnext; pnext = &((*pnext)->next)) { 00698 if ((*pnext)->package == package) { 00699 t = q = strdup((*pnext)->typestr); 00700 if ((p = strchr(q, ':'))) *p++ = '\0'; 00701 /* Now p = renderer, e.g. "gd" 00702 * and q = device, e.g. "png" 00703 * or q = imageloader, e.g. "png" */ 00704 00705 /* hack for aliases */ 00706 if (!strncmp(q,"jp",2)) 00707 q = "jpeg/jpe/jpg"; 00708 else if (!strncmp(q,"tif",3)) 00709 q = "tiff/tif"; 00710 else if (!strcmp(q,"x11") || !strcmp(q,"xlib")) 00711 q = "x11/xlib"; 00712 else if (!strcmp(q,"dot") || !strcmp(q,"gv")) 00713 q = "gv/dot"; 00714 00715 switch (api) { 00716 case API_device: 00717 strcpy(buf2, q); 00718 #ifndef WITH_CGRAPH 00719 n = agnode(g, bufa); 00720 #else 00721 n = agnode(g, bufa, 1); 00722 #endif 00723 strcpy(bufb, "output_"); 00724 strcat(bufb, q); 00725 m = agfindnode(ssg, bufb); 00726 if (!m) { 00727 #ifndef WITH_CGRAPH 00728 m = agnode(ssg, bufb); 00729 #else 00730 m = agnode(ssg, bufb, 1); 00731 #endif 00732 a = agfindnodeattr(g, "label"); 00733 #ifndef WITH_CGRAPH 00734 agxset(m, a->index, q); 00735 #else 00736 agxset(m, a, q); 00737 #endif 00738 } 00739 e = agfindedge(g, n, m); 00740 if (!e) 00741 #ifndef WITH_CGRAPH 00742 e = agedge(g, n, m); 00743 #else 00744 e = agedge(g, n, m, NULL, 1); 00745 #endif 00746 if (p && *p) { 00747 strcpy(bufb, "render_"); 00748 strcat(bufb, p); 00749 m = agfindnode(ssg, bufb); 00750 if (!m) 00751 #ifndef WITH_CGRAPH 00752 m = agnode(g, bufb); 00753 #else 00754 m = agnode(g, bufb, 1); 00755 #endif 00756 e = agfindedge(g, m, n); 00757 if (!e) 00758 #ifndef WITH_CGRAPH 00759 e = agedge(g, m, n); 00760 #else 00761 e = agedge(g, m, n, NULL, 1); 00762 #endif 00763 } 00764 break; 00765 case API_loadimage: 00766 strcpy(buf2, q); 00767 #ifndef WITH_CGRAPH 00768 n = agnode(g, bufa); 00769 #else 00770 n = agnode(g, bufa, 1); 00771 #endif 00772 strcpy(bufb, "input_"); 00773 strcat(bufb, q); 00774 m = agfindnode(g, bufb); 00775 if (!m) { 00776 #ifndef WITH_CGRAPH 00777 m = agnode(g, bufb); 00778 #else 00779 m = agnode(g, bufb, 1); 00780 #endif 00781 a = agfindnodeattr(g, "label"); 00782 #ifndef WITH_CGRAPH 00783 agxset(m, a->index, q); 00784 #else 00785 agxset(m, a, q); 00786 #endif 00787 } 00788 e = agfindedge(g, m, n); 00789 if (!e) 00790 #ifndef WITH_CGRAPH 00791 e = agedge(g, m, n); 00792 #else 00793 e = agedge(g, m, n, NULL, 1); 00794 #endif 00795 strcpy(bufb, "render_"); 00796 strcat(bufb, p); 00797 m = agfindnode(g, bufb); 00798 if (!m) 00799 #ifndef WITH_CGRAPH 00800 m = agnode(g, bufb); 00801 #else 00802 m = agnode(g, bufb, 1); 00803 #endif 00804 e = agfindedge(g, n, m); 00805 if (!e) 00806 #ifndef WITH_CGRAPH 00807 e = agedge(g, n, m); 00808 #else 00809 e = agedge(g, n, m, NULL, 1); 00810 #endif 00811 break; 00812 default: 00813 break; 00814 } 00815 free(t); 00816 } 00817 } 00818 } 00819 } 00820 00821 return g; 00822 }
1.7.5