|
Graphviz
2.31.20130520.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 #ifdef WIN32 00039 #define strdup(x) _strdup(x) 00040 #endif 00041 00042 /* 00043 * Define an apis array of name strings using an enumerated api_t as index. 00044 * The enumerated type is defined gvplugin.h. The apis array is 00045 * inititialized here by redefining ELEM and reinvoking APIS. 00046 */ 00047 #define ELEM(x) #x, 00048 static char *api_names[] = { APIS }; /* "render", "layout", ... */ 00049 #undef ELEM 00050 00051 /* translate a string api name to its type, or -1 on error */ 00052 api_t gvplugin_api(char *str) 00053 { 00054 int api; 00055 00056 for (api = 0; api < ARRAY_SIZE(api_names); api++) { 00057 if (strcmp(str, api_names[api]) == 0) 00058 return (api_t)api; 00059 } 00060 return -1; /* invalid api */ 00061 } 00062 00063 /* translate api_t into string name, or NULL */ 00064 char *gvplugin_api_name(api_t api) 00065 { 00066 if (api < 0 || api >= ARRAY_SIZE(api_names)) 00067 return NULL; 00068 return api_names[api]; 00069 } 00070 00071 /* install a plugin description into the list of available plugins 00072 * list is alpha sorted by type (not including :dependency), then 00073 * quality sorted within the type, then, if qualities are the same, 00074 * last install wins. 00075 */ 00076 boolean gvplugin_install(GVC_t * gvc, api_t api, const char *typestr, 00077 int quality, gvplugin_package_t *package, 00078 gvplugin_installed_t * typeptr) 00079 { 00080 gvplugin_available_t *plugin, **pnext; 00081 #define TYPSIZ 63 00082 char *p, pins[TYPSIZ+1], pnxt[TYPSIZ+1]; 00083 00084 if (api < 0) 00085 return FALSE; 00086 00087 strncpy(pins, typestr, TYPSIZ); 00088 if ((p = strchr(pins, ':'))) 00089 *p = '\0'; 00090 00091 /* point to the beginning of the linked list of plugins for this api */ 00092 pnext = &(gvc->apis[api]); 00093 00094 /* keep alpha-sorted and insert new duplicates ahead of old */ 00095 while (*pnext) { 00096 strncpy(pnxt, (*pnext)->typestr, TYPSIZ); 00097 if ((p = strchr(pnxt, ':'))) 00098 *p = '\0'; 00099 if (strcmp(pins, pnxt) <= 0) 00100 break; 00101 pnext = &((*pnext)->next); 00102 } 00103 00104 /* keep quality sorted within type and insert new duplicates ahead of old */ 00105 while (*pnext) { 00106 strncpy(pnxt, (*pnext)->typestr, TYPSIZ); 00107 if ((p = strchr(pnxt, ':'))) 00108 *p = '\0'; 00109 if (strcmp(pins, pnxt) != 0) 00110 break; 00111 if (quality >= (*pnext)->quality) 00112 break; 00113 pnext = &((*pnext)->next); 00114 } 00115 00116 plugin = GNEW(gvplugin_available_t); 00117 plugin->next = *pnext; 00118 *pnext = plugin; 00119 plugin->typestr = typestr; 00120 plugin->quality = quality; 00121 plugin->package = package; 00122 plugin->typeptr = typeptr; /* null if not loaded */ 00123 00124 return TRUE; 00125 } 00126 00127 /* Activate a plugin description in the list of available plugins. 00128 * This is used when a plugin-library loaded because of demand for 00129 * one of its plugins. It updates the available plugin data with 00130 * pointers into the loaded library. 00131 * NB the quality value is not replaced as it might have been 00132 * manually changed in the config file. 00133 */ 00134 static boolean gvplugin_activate(GVC_t * gvc, api_t api, 00135 const char *typestr, char *name, char *path, 00136 gvplugin_installed_t * typeptr) 00137 { 00138 gvplugin_available_t **pnext; 00139 00140 00141 if (api < 0) 00142 return FALSE; 00143 00144 /* point to the beginning of the linked list of plugins for this api */ 00145 pnext = &(gvc->apis[api]); 00146 00147 while (*pnext) { 00148 if ( (strcasecmp(typestr, (*pnext)->typestr) == 0) 00149 && (strcasecmp(name, (*pnext)->package->name) == 0) 00150 && ((*pnext)->package->path != 0) 00151 && (strcasecmp(path, (*pnext)->package->path) == 0)) { 00152 (*pnext)->typeptr = typeptr; 00153 return TRUE; 00154 } 00155 pnext = &((*pnext)->next); 00156 } 00157 return FALSE; 00158 } 00159 00160 gvplugin_library_t *gvplugin_library_load(GVC_t *gvc, char *path) 00161 { 00162 #ifdef ENABLE_LTDL 00163 lt_dlhandle hndl; 00164 lt_ptr ptr; 00165 char *s, *sym; 00166 int len; 00167 static char *p; 00168 static int lenp; 00169 char *libdir; 00170 char *suffix = "_LTX_library"; 00171 00172 if (! gvc->common.demand_loading) 00173 return NULL; 00174 00175 libdir = gvconfig_libdir(gvc); 00176 len = strlen(libdir) + 1 + strlen(path) + 1; 00177 if (len > lenp) { 00178 lenp = len+20; 00179 if (p) 00180 p = grealloc(p, lenp); 00181 else 00182 p = gmalloc(lenp); 00183 } 00184 00185 #ifdef WIN32 00186 if (path[1] == ':') { 00187 #else 00188 if (path[0] == '/') { 00189 #endif 00190 strcpy(p, path); 00191 } else { 00192 strcpy(p, libdir); 00193 strcat(p, DIRSEP); 00194 strcat(p, path); 00195 } 00196 00197 if (lt_dlinit()) { 00198 agerr(AGERR, "failed to init libltdl\n"); 00199 return NULL; 00200 } 00201 hndl = lt_dlopen (p); 00202 if (!hndl) { 00203 agerr(AGWARN, "Could not load \"%s\" - %s\n", p, (char*)lt_dlerror()); 00204 return NULL; 00205 } 00206 if (gvc->common.verbose >= 2) 00207 fprintf(stderr, "Loading %s\n", p); 00208 00209 s = strrchr(p, DIRSEP[0]); 00210 len = strlen(s); 00211 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) 00212 if (len < strlen("/gvplugin_x")) { 00213 #else 00214 if (len < strlen("/libgvplugin_x")) { 00215 #endif 00216 agerr (AGERR,"invalid plugin path \"%s\"\n", p); 00217 return NULL; 00218 } 00219 sym = gmalloc(len + strlen(suffix) + 1); 00220 #if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) 00221 strcpy(sym, s+1); /* strip leading "/" */ 00222 #else 00223 strcpy(sym, s+4); /* strip leading "/lib" or "/cyg" */ 00224 #endif 00225 #if defined(__CYGWIN__) || defined(__MINGW32__) 00226 s = strchr(sym, '-'); /* strip trailing "-1.dll" */ 00227 #else 00228 s = strchr(sym, '.'); /* strip trailing ".so.0" or ".dll" or ".sl" */ 00229 #endif 00230 strcpy(s,suffix); /* append "_LTX_library" */ 00231 00232 ptr = lt_dlsym (hndl, sym); 00233 if (!ptr) { 00234 agerr (AGERR,"failed to resolve %s in %s\n", sym, p); 00235 free(sym); 00236 return NULL; 00237 } 00238 free(sym); 00239 return (gvplugin_library_t *)(ptr); 00240 #else 00241 agerr (AGERR,"dynamic loading not available\n"); 00242 return NULL; 00243 #endif 00244 } 00245 00246 00247 /* load a plugin of type=str 00248 the str can optionally contain one or more ":dependencies" 00249 00250 examples: 00251 png 00252 png:cairo 00253 fully qualified: 00254 png:cairo:cairo 00255 png:cairo:gd 00256 png:gd:gd 00257 00258 */ 00259 gvplugin_available_t *gvplugin_load(GVC_t * gvc, api_t api, const char *str) 00260 { 00261 gvplugin_available_t **pnext, *rv; 00262 gvplugin_library_t *library; 00263 gvplugin_api_t *apis; 00264 gvplugin_installed_t *types; 00265 #define TYPBUFSIZ 64 00266 char reqtyp[TYPBUFSIZ], typ[TYPBUFSIZ]; 00267 char *reqdep, *dep = NULL, *reqpkg; 00268 int i; 00269 api_t apidep; 00270 00271 /* check for valid apis[] index */ 00272 if (api < 0) 00273 return NULL; 00274 00275 if (api == API_device 00276 || api == API_loadimage) /* api dependencies - FIXME - find better way to code these *s */ 00277 00278 apidep = API_render; 00279 else 00280 apidep = api; 00281 00282 strncpy(reqtyp, str, TYPBUFSIZ-1); 00283 reqdep = strchr(reqtyp, ':'); 00284 if (reqdep) { 00285 *reqdep++ = '\0'; 00286 reqpkg = strchr(reqdep, ':'); 00287 if (reqpkg) 00288 *reqpkg++ = '\0'; 00289 } 00290 else 00291 reqpkg = NULL; 00292 00293 /* iterate the linked list of plugins for this api */ 00294 for (pnext = &(gvc->apis[api]); *pnext; pnext = &((*pnext)->next)) { 00295 strncpy(typ, (*pnext)->typestr, TYPBUFSIZ-1); 00296 dep = strchr(typ, ':'); 00297 if (dep) 00298 *dep++ = '\0'; 00299 if (strcmp(typ, reqtyp)) 00300 continue; /* types empty or mismatched */ 00301 if (dep && reqdep && strcmp(dep, reqdep)) 00302 continue; /* dependencies not empty, but mismatched */ 00303 if (! reqpkg || strcmp(reqpkg, (*pnext)->package->name) == 0) 00304 { 00305 /* found with no packagename constraints, or with required matching packagname */ 00306 00307 if (dep && (apidep != api)) /* load dependency if needed, continue if can't find */ 00308 if (! (gvplugin_load(gvc, apidep, dep))) 00309 continue; 00310 break; 00311 } 00312 } 00313 rv = *pnext; 00314 00315 if (rv && rv->typeptr == NULL) { 00316 library = gvplugin_library_load(gvc, rv->package->path); 00317 if (library) { 00318 00319 /* Now activate the library with real type ptrs */ 00320 for (apis = library->apis; (types = apis->types); apis++) { 00321 for (i = 0; types[i].type; i++) { 00322 /* NB. quality is not checked or replaced 00323 * in case user has manually edited quality in config */ 00324 gvplugin_activate(gvc, 00325 apis->api, 00326 types[i].type, 00327 library->packagename, 00328 rv->package->path, 00329 &types[i]); 00330 } 00331 } 00332 if (gvc->common.verbose >= 1) 00333 fprintf(stderr, "Activated plugin library: %s\n", 00334 rv->package->path ? rv->package->path : "<builtin>"); 00335 } 00336 } 00337 00338 /* one last check for successfull load */ 00339 if (rv && rv->typeptr == NULL) 00340 rv = NULL; 00341 00342 if (rv && gvc->common.verbose >= 1) 00343 fprintf(stderr, "Using %s: %s:%s\n", 00344 api_names[api], 00345 rv->typestr, 00346 rv->package->name 00347 ); 00348 00349 gvc->api[api] = rv; 00350 return rv; 00351 } 00352 00353 /* assemble a string list of available plugins 00354 * non-re-entrant as character store is shared 00355 */ 00356 char *gvplugin_list(GVC_t * gvc, api_t api, const char *str) 00357 { 00358 static int first = 1; 00359 gvplugin_available_t **pnext, **plugin; 00360 char *bp; 00361 char *s, *p, *q, *typestr_last; 00362 boolean new = TRUE; 00363 static agxbuf xb; 00364 00365 /* check for valid apis[] index */ 00366 if (api < 0) 00367 return NULL; 00368 00369 /* check for valid str */ 00370 if (! str) 00371 return NULL; 00372 00373 if (first) { 00374 agxbinit(&xb, 0, 0); 00375 first = 0; 00376 } 00377 00378 /* does str have a :path modifier? */ 00379 s = strdup(str); 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