|
Graphviz
2.31.20130618.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 #include <ctype.h> 00015 #include "render.h" 00016 #include "htmltable.h" 00017 #include "gvc.h" 00018 #include "xdot.h" 00019 #include "agxbuf.h" 00020 00021 static char *usageFmt = 00022 "Usage: %s [-Vv?] [-(GNE)name=val] [-(KTlso)<val>] <dot files>\n"; 00023 00024 static char *genericItems = "\n\ 00025 -V - Print version and exit\n\ 00026 -v - Enable verbose mode \n\ 00027 -Gname=val - Set graph attribute 'name' to 'val'\n\ 00028 -Nname=val - Set node attribute 'name' to 'val'\n\ 00029 -Ename=val - Set edge attribute 'name' to 'val'\n\ 00030 -Tv - Set output format to 'v'\n\ 00031 -Kv - Set layout engine to 'v' (overrides default based on command name)\n\ 00032 -lv - Use external library 'v'\n\ 00033 -ofile - Write output to 'file'\n\ 00034 -O - Automatically generate an output filename based on the input filename with a .'format' appended. (Causes all -ofile options to be ignored.) \n\ 00035 -P - Internally generate a graph of the current plugins. \n\ 00036 -q[l] - Set level of message suppression (=1)\n\ 00037 -s[v] - Scale input by 'v' (=72)\n\ 00038 -y - Invert y coordinate in output\n"; 00039 00040 static char *neatoFlags = 00041 "(additional options for neato) [-x] [-n<v>]\n"; 00042 static char *neatoItems = "\n\ 00043 -n[v] - No layout mode 'v' (=1)\n\ 00044 -x - Reduce graph\n"; 00045 00046 static char *fdpFlags = 00047 "(additional options for fdp) [-L(gO)] [-L(nUCT)<val>]\n"; 00048 static char *fdpItems = "\n\ 00049 -Lg - Don't use grid\n\ 00050 -LO - Use old attractive force\n\ 00051 -Ln<i> - Set number of iterations to i\n\ 00052 -LU<i> - Set unscaled factor to i\n\ 00053 -LC<v> - Set overlap expansion factor to v\n\ 00054 -LT[*]<v> - Set temperature (temperature factor) to v\n"; 00055 00056 static char *memtestFlags = "(additional options for memtest) [-m<v>]\n"; 00057 static char *memtestItems = "\n\ 00058 -m - Memory test (Observe no growth with top. Kill when done.)\n\ 00059 -m[v] - Memory test - v iterations.\n"; 00060 00061 static char *configFlags = "(additional options for config) [-cv]\n"; 00062 static char *configItems = "\n\ 00063 -c - Configure plugins (Writes $prefix/lib/graphviz/config \n\ 00064 with available plugin information. Needs write privilege.)\n\ 00065 -? - Print usage and exit\n"; 00066 00067 /* dotneato_usage: 00068 * Print usage information. If GvExitOnUsage is set, exit with 00069 * given exval, else return exval+1. 00070 */ 00071 int dotneato_usage(int exval) 00072 { 00073 FILE *outs; 00074 00075 if (exval > 0) 00076 outs = stderr; 00077 else 00078 outs = stdout; 00079 00080 fprintf(outs, usageFmt, CmdName); 00081 fputs(neatoFlags, outs); 00082 fputs(fdpFlags, outs); 00083 fputs(memtestFlags, outs); 00084 fputs(configFlags, outs); 00085 fputs(genericItems, outs); 00086 fputs(neatoItems, outs); 00087 fputs(fdpItems, outs); 00088 fputs(memtestItems, outs); 00089 fputs(configItems, outs); 00090 00091 if (GvExitOnUsage && (exval >= 0)) 00092 exit(exval); 00093 return (exval+1); 00094 00095 } 00096 00097 /* getFlagOpt: 00098 * Look for flag parameter. idx is index of current argument. 00099 * We assume argv[*idx] has the form "-x..." If there are characters 00100 * after the x, return 00101 * these, else if there are more arguments, return the next one, 00102 * else return NULL. 00103 */ 00104 static char *getFlagOpt(int argc, char **argv, int *idx) 00105 { 00106 int i = *idx; 00107 char *arg = argv[i]; 00108 00109 if (arg[2]) 00110 return arg + 2; 00111 if (i < argc - 1) { 00112 i++; 00113 arg = argv[i]; 00114 if (*arg && (*arg != '-')) { 00115 *idx = i; 00116 return arg; 00117 } 00118 } 00119 return 0; 00120 } 00121 00122 /* dotneato_basename: 00123 * Partial implementation of real basename. 00124 * Skip over any trailing slashes or backslashes; then 00125 * find next (back)slash moving left; return string to the right. 00126 * If no next slash is found, return the whole string. 00127 */ 00128 static char* dotneato_basename (char* path) 00129 { 00130 char* ret; 00131 char* s = path; 00132 if (*s == '\0') return path; /* empty string */ 00133 #ifdef WIN32 00134 /* On Windows, executables, by convention, end in ".exe". Thus, 00135 * this may be part of the path name and must be removed for 00136 * matching to work. 00137 */ 00138 { 00139 char* dotp = strrchr (s, '.'); 00140 if (dotp && !strcasecmp(dotp+1,"exe")) *dotp = '\0'; 00141 } 00142 #endif 00143 while (*s) s++; s--; 00144 /* skip over trailing slashes, nulling out as we go */ 00145 while ((s > path) && ((*s == '/') || (*s == '\\'))) 00146 *s-- = '\0'; 00147 if (s == path) ret = path; 00148 else { 00149 while ((s > path) && ((*s != '/') && (*s != '\\'))) s--; 00150 if ((*s == '/') || (*s == '\\')) ret = s+1; 00151 else ret = path; 00152 } 00153 #ifdef WIN32 00154 /* On Windows, names are case-insensitive, so make name lower-case 00155 */ 00156 { 00157 char c; 00158 for (s = ret; (c = *s); s++) 00159 *s = tolower(c); 00160 } 00161 #endif 00162 return ret; 00163 } 00164 00165 static void use_library(GVC_t *gvc, const char *name) 00166 { 00167 static int cnt = 0; 00168 if (name) { 00169 Lib = ALLOC(cnt + 2, Lib, const char *); 00170 Lib[cnt++] = name; 00171 Lib[cnt] = NULL; 00172 } 00173 gvc->common.lib = Lib; 00174 } 00175 00176 #ifdef WITH_CGRAPH 00177 static void global_def(agxbuf* xb, char *dcl, int kind, 00178 attrsym_t * ((*dclfun) (Agraph_t *, int kind, char *, char *)) ) 00179 { 00180 char *p; 00181 char *rhs = "true"; 00182 00183 attrsym_t *sym; 00184 if ((p = strchr(dcl, '='))) { 00185 agxbput_n (xb, dcl, p-dcl); 00186 rhs = p+1; 00187 } 00188 else 00189 agxbput (xb, dcl); 00190 sym = dclfun(NULL, kind, agxbuse (xb), rhs); 00191 sym->fixed = 1; 00192 } 00193 #else 00194 static void global_def(agxbuf* xb, char *dcl, 00195 attrsym_t * ((*dclfun) (Agraph_t *, char *, char *))) 00196 { 00197 char *p; 00198 char *rhs = "true"; 00199 00200 attrsym_t *sym; 00201 if ((p = strchr(dcl, '='))) { 00202 agxbput_n (xb, dcl, p-dcl); 00203 rhs = p+1; 00204 } 00205 else 00206 agxbput (xb, dcl); 00207 sym = dclfun(NULL, agxbuse (xb), rhs); 00208 sym->fixed = 1; 00209 } 00210 #endif 00211 00212 static int gvg_init(GVC_t *gvc, graph_t *g, char *fn, int gidx) 00213 { 00214 GVG_t *gvg; 00215 00216 gvg = zmalloc(sizeof(GVG_t)); 00217 if (!gvc->gvgs) 00218 gvc->gvgs = gvg; 00219 else 00220 gvc->gvg->next = gvg; 00221 gvc->gvg = gvg; 00222 gvg->gvc = gvc; 00223 gvg->g = g; 00224 gvg->input_filename = fn; 00225 gvg->graph_index = gidx; 00226 return 0; 00227 } 00228 00229 static graph_t *P_graph; 00230 00231 graph_t *gvPluginsGraph(GVC_t *gvc) 00232 { 00233 gvg_init(gvc, P_graph, "<internal>", 0); 00234 return P_graph; 00235 } 00236 00237 /* dotneato_args_initialize" 00238 * Scan argv[] for allowed flags. 00239 * Return 0 on success; v+1 if calling function should call exit(v). 00240 * If -c is set, config file is created and we exit. 00241 */ 00242 int dotneato_args_initialize(GVC_t * gvc, int argc, char **argv) 00243 { 00244 char c, *rest, *layout; 00245 const char *val; 00246 int i, v, nfiles; 00247 unsigned char buf[SMALLBUF]; 00248 agxbuf xb; 00249 int Kflag = 0; 00250 00251 /* establish if we are running in a CGI environment */ 00252 HTTPServerEnVar = getenv("SERVER_NAME"); 00253 00254 /* establish Gvfilepath, if any */ 00255 Gvfilepath = getenv("GV_FILE_PATH"); 00256 00257 gvc->common.cmdname = dotneato_basename(argv[0]); 00258 if (gvc->common.verbose) { 00259 fprintf(stderr, "%s - %s version %s (%s)\n", 00260 gvc->common.cmdname, gvc->common.info[0], 00261 gvc->common.info[1], gvc->common.info[2]); 00262 } 00263 00264 /* configure for available plugins */ 00265 /* needs to know if "dot -c" is set (gvc->common.config) */ 00266 /* must happen before trying to select any plugins */ 00267 gvconfig(gvc, gvc->common.config); 00268 if (gvc->common.config) 00269 exit (0); 00270 00271 /* feed the globals */ 00272 Verbose = gvc->common.verbose; 00273 CmdName = gvc->common.cmdname; 00274 00275 #ifndef WITH_CGRAPH 00276 aginit(); 00277 #endif 00278 nfiles = 0; 00279 for (i = 1; i < argc; i++) 00280 if (argv[i] && argv[i][0] != '-') 00281 nfiles++; 00282 gvc->input_filenames = N_NEW(nfiles + 1, char *); 00283 nfiles = 0; 00284 agxbinit(&xb, SMALLBUF, buf); 00285 for (i = 1; i < argc; i++) { 00286 if (argv[i] && argv[i][0] == '-') { 00287 rest = &(argv[i][2]); 00288 switch (c = argv[i][1]) { 00289 case 'G': 00290 if (*rest) 00291 #ifdef WITH_CGRAPH 00292 global_def(&xb, rest, AGRAPH, agattr); 00293 #else 00294 global_def(&xb, rest, agraphattr); 00295 #endif 00296 else { 00297 fprintf(stderr, "Missing argument for -G flag\n"); 00298 return (dotneato_usage(1)); 00299 } 00300 break; 00301 case 'N': 00302 if (*rest) 00303 #ifdef WITH_CGRAPH 00304 global_def(&xb, rest, AGNODE,agattr); 00305 #else 00306 global_def(&xb, rest, agnodeattr); 00307 #endif 00308 else { 00309 fprintf(stderr, "Missing argument for -N flag\n"); 00310 return (dotneato_usage(1)); 00311 } 00312 break; 00313 case 'E': 00314 if (*rest) 00315 #ifdef WITH_CGRAPH 00316 global_def(&xb, rest, AGEDGE,agattr); 00317 #else 00318 global_def(&xb, rest, agedgeattr); 00319 #endif 00320 else { 00321 fprintf(stderr, "Missing argument for -E flag\n"); 00322 return (dotneato_usage(1)); 00323 } 00324 break; 00325 case 'T': 00326 val = getFlagOpt(argc, argv, &i); 00327 if (!val) { 00328 fprintf(stderr, "Missing argument for -T flag\n"); 00329 return (dotneato_usage(1)); 00330 } 00331 v = gvjobs_output_langname(gvc, val); 00332 if (!v) { 00333 fprintf(stderr, "Format: \"%s\" not recognized. Use one of:%s\n", 00334 val, gvplugin_list(gvc, API_device, val)); 00335 if (GvExitOnUsage) exit(1); 00336 return(2); 00337 } 00338 break; 00339 case 'K': 00340 val = getFlagOpt(argc, argv, &i); 00341 if (!val) { 00342 fprintf(stderr, "Missing argument for -K flag\n"); 00343 return (dotneato_usage(1)); 00344 } 00345 v = gvlayout_select(gvc, val); 00346 if (v == NO_SUPPORT) { 00347 fprintf(stderr, "There is no layout engine support for \"%s\"\n", val); 00348 if (streq(val, "dot")) { 00349 fprintf(stderr, "Perhaps \"dot -c\" needs to be run (with installer's privileges) to register the plugins?\n"); 00350 } 00351 else { 00352 fprintf(stderr, "Use one of:%s\n", 00353 gvplugin_list(gvc, API_layout, val)); 00354 } 00355 if (GvExitOnUsage) exit(1); 00356 return(2); 00357 } 00358 Kflag = 1; 00359 break; 00360 case 'P': 00361 P_graph = gvplugin_graph(gvc); 00362 break; 00363 case 'V': 00364 fprintf(stderr, "%s - %s version %s (%s)\n", 00365 gvc->common.cmdname, gvc->common.info[0], 00366 gvc->common.info[1], gvc->common.info[2]); 00367 if (GvExitOnUsage) exit(0); 00368 return (1); 00369 break; 00370 case 'l': 00371 val = getFlagOpt(argc, argv, &i); 00372 if (!val) { 00373 fprintf(stderr, "Missing argument for -l flag\n"); 00374 return (dotneato_usage(1)); 00375 } 00376 use_library(gvc, val); 00377 break; 00378 case 'o': 00379 val = getFlagOpt(argc, argv, &i); 00380 if (! gvc->common.auto_outfile_names) 00381 gvjobs_output_filename(gvc, val); 00382 break; 00383 case 'q': 00384 if (*rest) { 00385 v = atoi(rest); 00386 if (v <= 0) { 00387 fprintf(stderr, 00388 "Invalid parameter \"%s\" for -q flag - ignored\n", 00389 rest); 00390 } else if (v == 1) 00391 agseterr(AGERR); 00392 else 00393 agseterr(AGMAX); 00394 } else 00395 agseterr(AGERR); 00396 break; 00397 case 's': 00398 if (*rest) { 00399 PSinputscale = atof(rest); 00400 if (PSinputscale <= 0) { 00401 fprintf(stderr, 00402 "Invalid parameter \"%s\" for -s flag\n", 00403 rest); 00404 return (dotneato_usage(1)); 00405 } 00406 } else 00407 PSinputscale = POINTS_PER_INCH; 00408 break; 00409 case 'x': 00410 Reduce = TRUE; 00411 break; 00412 case 'y': 00413 Y_invert = TRUE; 00414 break; 00415 case '?': 00416 return (dotneato_usage(0)); 00417 break; 00418 default: 00419 agerr(AGERR, "%s: option -%c unrecognized\n\n", gvc->common.cmdname, 00420 c); 00421 return (dotneato_usage(1)); 00422 } 00423 } else if (argv[i]) 00424 gvc->input_filenames[nfiles++] = argv[i]; 00425 } 00426 agxbfree (&xb); 00427 00428 /* if no -K, use cmd name to set layout type */ 00429 if (!Kflag) { 00430 layout = gvc->common.cmdname; 00431 if (streq(layout, "dot_static") 00432 || streq(layout, "dot_builtins") 00433 || streq(layout, "lt-dot") 00434 || streq(layout, "lt-dot_builtins") 00435 || streq(layout, "") /* when run as a process from Gvedit on Windows */ 00436 ) 00437 layout = "dot"; 00438 i = gvlayout_select(gvc, layout); 00439 if (i == NO_SUPPORT) { 00440 fprintf(stderr, "There is no layout engine support for \"%s\"\n", layout); 00441 if (streq(layout, "dot")) 00442 fprintf(stderr, "Perhaps \"dot -c\" needs to be run (with installer's privileges) to register the plugins?\n"); 00443 else 00444 fprintf(stderr, "Use one of:%s\n", gvplugin_list(gvc, API_layout, "")); 00445 00446 if (GvExitOnUsage) exit(1); 00447 return(2); 00448 } 00449 } 00450 00451 /* if no -Txxx, then set default format */ 00452 if (!gvc->jobs || !gvc->jobs->output_langname) { 00453 v = gvjobs_output_langname(gvc, "dot"); 00454 if (!v) { 00455 // assert(v); /* "dot" should always be available as an output format */ 00456 fprintf(stderr, 00457 "Unable to find even the default \"-Tdot\" renderer. Has the config\nfile been generated by running \"dot -c\" with installer's priviledges?\n"); 00458 return(2); 00459 } 00460 } 00461 00462 /* set persistent attributes here (if not already set from command line options) */ 00463 #ifdef WITH_CGRAPH 00464 if (!agattr(NULL, AGNODE, "label", 0)) 00465 agattr(NULL, AGNODE, "label", NODENAME_ESC); 00466 #else 00467 if (!(agfindnodeattr(agprotograph(), "label"))) 00468 agnodeattr(NULL, "label", NODENAME_ESC); 00469 #endif 00470 return 0; 00471 } 00472 00473 /* getdoubles2ptf: 00474 * converts a graph attribute in inches to a pointf in points. 00475 * If only one number is given, it is used for both x and y. 00476 * Returns true if the attribute ends in '!'. 00477 */ 00478 static boolean getdoubles2ptf(graph_t * g, char *name, pointf * result) 00479 { 00480 char *p; 00481 int i; 00482 double xf, yf; 00483 char c = '\0'; 00484 boolean rv = FALSE; 00485 00486 if ((p = agget(g, name))) { 00487 i = sscanf(p, "%lf,%lf%c", &xf, &yf, &c); 00488 if ((i > 1) && (xf > 0) && (yf > 0)) { 00489 result->x = POINTS(xf); 00490 result->y = POINTS(yf); 00491 if (c == '!') 00492 rv = TRUE; 00493 } 00494 else { 00495 c = '\0'; 00496 i = sscanf(p, "%lf%c", &xf, &c); 00497 if ((i > 0) && (xf > 0)) { 00498 result->y = result->x = POINTS(xf); 00499 if (c == '!') rv = TRUE; 00500 } 00501 } 00502 } 00503 return rv; 00504 } 00505 00506 void getdouble(graph_t * g, char *name, double *result) 00507 { 00508 char *p; 00509 double f; 00510 00511 if ((p = agget(g, name))) { 00512 if (sscanf(p, "%lf", &f) >= 1) 00513 *result = f; 00514 } 00515 } 00516 00517 #ifdef EXPERIMENTAL_MYFGETS 00518 /* 00519 * Potential input filter - e.g. for iconv 00520 */ 00521 00522 /* 00523 * myfgets - same api as fgets 00524 * 00525 * gets n chars at a time 00526 * 00527 * returns pointer to user buffer, 00528 * or returns NULL on eof or error. 00529 */ 00530 static char *myfgets(char * ubuf, int n, FILE * fp) 00531 { 00532 static char *buf; 00533 static int bufsz, pos, len; 00534 int cnt; 00535 00536 if (!n) { /* a call with n==0 (from aglexinit) resets */ 00537 ubuf[0] = '\0'; 00538 pos = len = 0; 00539 return NULL; 00540 } 00541 00542 if (!len) { 00543 if (n > bufsz) { 00544 bufsz = n; 00545 buf = realloc(buf, bufsz); 00546 } 00547 if (!(fgets(buf, bufsz, fp))) { 00548 ubuf[0] = '\0'; 00549 return NULL; 00550 } 00551 len = strlen(buf); 00552 pos = 0; 00553 } 00554 00555 cnt = n - 1; 00556 if (len < cnt) 00557 cnt = len; 00558 00559 memcpy(ubuf, buf + pos, cnt); 00560 pos += cnt; 00561 len -= cnt; 00562 ubuf[cnt] = '\0'; 00563 00564 return ubuf; 00565 } 00566 #endif 00567 00568 graph_t *gvNextInputGraph(GVC_t *gvc) 00569 { 00570 graph_t *g = NULL; 00571 static char *fn; 00572 static FILE *fp; 00573 static int fidx, gidx; 00574 00575 while (!g) { 00576 if (!fp) { 00577 if (!(fn = gvc->input_filenames[0])) { 00578 if (fidx++ == 0) 00579 fp = stdin; 00580 } 00581 else { 00582 while ((fn = gvc->input_filenames[fidx++]) && !(fp = fopen(fn, "r"))) { 00583 agerr(AGERR, "%s: can't open %s\n", gvc->common.cmdname, fn); 00584 graphviz_errors++; 00585 } 00586 } 00587 } 00588 if (fp == NULL) 00589 break; 00590 agsetfile(fn ? fn : "<stdin>"); 00591 #ifdef EXPERIMENTAL_MYFGETS 00592 g = agread_usergets(fp, myfgets); 00593 #else 00594 #ifdef WITH_CGRAPH 00595 g = agread(fp,NIL(Agdisc_t*)); 00596 #else 00597 g = agread(fp); 00598 #endif 00599 #endif 00600 if (g) { 00601 gvg_init(gvc, g, fn, gidx++); 00602 break; 00603 } 00604 if (fp != stdin) 00605 fclose (fp); 00606 fp = NULL; 00607 gidx = 0; 00608 } 00609 return g; 00610 } 00611 00612 /* findCharset: 00613 * Check if the charset attribute is defined for the graph and, if 00614 * so, return the corresponding internal value. If undefined, return 00615 * CHAR_UTF8 00616 */ 00617 static int findCharset (graph_t * g) 00618 { 00619 int enc; 00620 char* p; 00621 00622 p = late_nnstring(g,agfindgraphattr(g,"charset"),"utf-8"); 00623 if (!strcasecmp(p,"latin-1") 00624 || !strcasecmp(p,"latin1") 00625 || !strcasecmp(p,"l1") 00626 || !strcasecmp(p,"ISO-8859-1") 00627 || !strcasecmp(p,"ISO_8859-1") 00628 || !strcasecmp(p,"ISO8859-1") 00629 || !strcasecmp(p,"ISO-IR-100")) 00630 enc = CHAR_LATIN1; 00631 else if (!strcasecmp(p,"big-5") 00632 || !strcasecmp(p,"big5")) 00633 enc = CHAR_BIG5; 00634 else if (!strcasecmp(p,"utf-8") 00635 || !strcasecmp(p,"utf8")) 00636 enc = CHAR_UTF8; 00637 else { 00638 agerr(AGWARN, "Unsupported charset \"%s\" - assuming utf-8\n", p); 00639 enc = CHAR_UTF8; 00640 } 00641 return enc; 00642 } 00643 00644 /* setRatio: 00645 * Checks "ratio" attribute, if any, and sets enum type. 00646 */ 00647 static void setRatio(graph_t * g) 00648 { 00649 char *p, c; 00650 double ratio; 00651 00652 if ((p = agget(g, "ratio")) && ((c = p[0]))) { 00653 switch (c) { 00654 case 'a': 00655 if (streq(p, "auto")) 00656 GD_drawing(g)->ratio_kind = R_AUTO; 00657 break; 00658 case 'c': 00659 if (streq(p, "compress")) 00660 GD_drawing(g)->ratio_kind = R_COMPRESS; 00661 break; 00662 case 'e': 00663 if (streq(p, "expand")) 00664 GD_drawing(g)->ratio_kind = R_EXPAND; 00665 break; 00666 case 'f': 00667 if (streq(p, "fill")) 00668 GD_drawing(g)->ratio_kind = R_FILL; 00669 break; 00670 default: 00671 ratio = atof(p); 00672 if (ratio > 0.0) { 00673 GD_drawing(g)->ratio_kind = R_VALUE; 00674 GD_drawing(g)->ratio = ratio; 00675 } 00676 break; 00677 } 00678 } 00679 } 00680 00681 /* 00682 cgraph requires 00683 00684 */ 00685 void graph_init(graph_t * g, boolean use_rankdir) 00686 { 00687 char *p; 00688 double xf; 00689 static char *rankname[] = { "local", "global", "none", NULL }; 00690 static int rankcode[] = { LOCAL, GLOBAL, NOCLUST, LOCAL }; 00691 static char *fontnamenames[] = {"gd","ps","svg", NULL}; 00692 static int fontnamecodes[] = {NATIVEFONTS,PSFONTS,SVGFONTS,-1}; 00693 int rankdir; 00694 GD_drawing(g) = NEW(layout_t); 00695 00696 /* set this up fairly early in case any string sizes are needed */ 00697 if ((p = agget(g, "fontpath")) || (p = getenv("DOTFONTPATH"))) { 00698 /* overide GDFONTPATH in local environment if dot 00699 * wants its own */ 00700 #ifdef HAVE_SETENV 00701 setenv("GDFONTPATH", p, 1); 00702 #else 00703 static char *buf = 0; 00704 00705 buf = grealloc(buf, strlen("GDFONTPATH=") + strlen(p) + 1); 00706 strcpy(buf, "GDFONTPATH="); 00707 strcat(buf, p); 00708 putenv(buf); 00709 #endif 00710 } 00711 00712 GD_charset(g) = findCharset (g); 00713 00714 if (!HTTPServerEnVar) { 00715 Gvimagepath = agget (g, "imagepath"); 00716 if (!Gvimagepath) 00717 Gvimagepath = Gvfilepath; 00718 } 00719 00720 GD_drawing(g)->quantum = 00721 late_double(g, agfindgraphattr(g, "quantum"), 0.0, 0.0); 00722 00723 /* setting rankdir=LR is only defined in dot, 00724 * but having it set causes shape code and others to use it. 00725 * The result is confused output, so we turn it off unless requested. 00726 * This effective rankdir is stored in the bottom 2 bits of g->u.rankdir. 00727 * Sometimes, the code really needs the graph's rankdir, e.g., neato -n 00728 * with record shapes, so we store the real rankdir in the next 2 bits. 00729 */ 00730 rankdir = RANKDIR_TB; 00731 if ((p = agget(g, "rankdir"))) { 00732 if (streq(p, "LR")) 00733 rankdir = RANKDIR_LR; 00734 else if (streq(p, "BT")) 00735 rankdir = RANKDIR_BT; 00736 else if (streq(p, "RL")) 00737 rankdir = RANKDIR_RL; 00738 } 00739 if (use_rankdir) 00740 SET_RANKDIR (g, (rankdir << 2) | rankdir); 00741 else 00742 SET_RANKDIR (g, (rankdir << 2)); 00743 00744 xf = late_double(g, agfindgraphattr(g, "nodesep"), 00745 DEFAULT_NODESEP, MIN_NODESEP); 00746 GD_nodesep(g) = POINTS(xf); 00747 00748 p = late_string(g, agfindgraphattr(g, "ranksep"), NULL); 00749 if (p) { 00750 if (sscanf(p, "%lf", &xf) == 0) 00751 xf = DEFAULT_RANKSEP; 00752 else { 00753 if (xf < MIN_RANKSEP) 00754 xf = MIN_RANKSEP; 00755 } 00756 if (strstr(p, "equally")) 00757 GD_exact_ranksep(g) = TRUE; 00758 } else 00759 xf = DEFAULT_RANKSEP; 00760 GD_ranksep(g) = POINTS(xf); 00761 00762 GD_showboxes(g) = late_int(g, agfindgraphattr(g, "showboxes"), 0, 0); 00763 p = late_string(g, agfindgraphattr(g, "fontnames"), NULL); 00764 GD_fontnames(g) = maptoken(p, fontnamenames, fontnamecodes); 00765 00766 setRatio(g); 00767 GD_drawing(g)->filled = 00768 getdoubles2ptf(g, "size", &(GD_drawing(g)->size)); 00769 getdoubles2ptf(g, "page", &(GD_drawing(g)->page)); 00770 00771 GD_drawing(g)->centered = mapbool(agget(g, "center")); 00772 00773 if ((p = agget(g, "rotate"))) 00774 GD_drawing(g)->landscape = (atoi(p) == 90); 00775 else if ((p = agget(g, "orientation"))) 00776 GD_drawing(g)->landscape = ((p[0] == 'l') || (p[0] == 'L')); 00777 else if ((p = agget(g, "landscape"))) 00778 GD_drawing(g)->landscape = mapbool(p); 00779 00780 p = agget(g, "clusterrank"); 00781 CL_type = maptoken(p, rankname, rankcode); 00782 p = agget(g, "concentrate"); 00783 Concentrate = mapbool(p); 00784 State = GVBEGIN; 00785 EdgeLabelsDone = 0; 00786 00787 GD_drawing(g)->dpi = 0.0; 00788 if (((p = agget(g, "dpi")) && p[0]) 00789 || ((p = agget(g, "resolution")) && p[0])) 00790 GD_drawing(g)->dpi = atof(p); 00791 00792 do_graph_label(g); 00793 00794 Initial_dist = MYHUGE; 00795 00796 G_ordering = agfindgraphattr(g, "ordering"); 00797 G_gradientangle = agfindgraphattr(g,"gradientangle"); 00798 G_margin = agfindgraphattr(g, "margin"); 00799 00800 /* initialize nodes */ 00801 N_height = agfindnodeattr(g, "height"); 00802 N_width = agfindnodeattr(g, "width"); 00803 N_shape = agfindnodeattr(g, "shape"); 00804 N_color = agfindnodeattr(g, "color"); 00805 N_fillcolor = agfindnodeattr(g, "fillcolor"); 00806 N_style = agfindnodeattr(g, "style"); 00807 N_fontsize = agfindnodeattr(g, "fontsize"); 00808 N_fontname = agfindnodeattr(g, "fontname"); 00809 N_fontcolor = agfindnodeattr(g, "fontcolor"); 00810 N_label = agfindnodeattr(g, "label"); 00811 N_xlabel = agfindnodeattr(g, "xlabel"); 00812 N_showboxes = agfindnodeattr(g, "showboxes"); 00813 N_penwidth = agfindnodeattr(g, "penwidth"); 00814 N_ordering = agfindnodeattr(g, "ordering"); 00815 N_margin = agfindnodeattr(g, "margin"); 00816 /* attribs for polygon shapes */ 00817 N_sides = agfindnodeattr(g, "sides"); 00818 N_peripheries = agfindnodeattr(g, "peripheries"); 00819 N_skew = agfindnodeattr(g, "skew"); 00820 N_orientation = agfindnodeattr(g, "orientation"); 00821 N_distortion = agfindnodeattr(g, "distortion"); 00822 N_fixed = agfindnodeattr(g, "fixedsize"); 00823 N_imagescale = agfindnodeattr(g, "imagescale"); 00824 N_nojustify = agfindnodeattr(g, "nojustify"); 00825 N_layer = agfindnodeattr(g, "layer"); 00826 N_group = agfindnodeattr(g, "group"); 00827 N_comment = agfindnodeattr(g, "comment"); 00828 N_vertices = agfindnodeattr(g, "vertices"); 00829 N_z = agfindnodeattr(g, "z"); 00830 N_gradientangle = agfindnodeattr(g,"gradientangle"); 00831 00832 /* initialize edges */ 00833 E_weight = agfindedgeattr(g, "weight"); 00834 E_color = agfindedgeattr(g, "color"); 00835 E_fillcolor = agfindedgeattr(g, "fillcolor"); 00836 E_fontsize = agfindedgeattr(g, "fontsize"); 00837 E_fontname = agfindedgeattr(g, "fontname"); 00838 E_fontcolor = agfindedgeattr(g, "fontcolor"); 00839 E_label = agfindedgeattr(g, "label"); 00840 E_xlabel = agfindedgeattr(g, "xlabel"); 00841 E_label_float = agfindedgeattr(g, "labelfloat"); 00842 /* vladimir */ 00843 E_dir = agfindedgeattr(g, "dir"); 00844 E_arrowhead = agfindedgeattr(g, "arrowhead"); 00845 E_arrowtail = agfindedgeattr(g, "arrowtail"); 00846 E_headlabel = agfindedgeattr(g, "headlabel"); 00847 E_taillabel = agfindedgeattr(g, "taillabel"); 00848 E_labelfontsize = agfindedgeattr(g, "labelfontsize"); 00849 E_labelfontname = agfindedgeattr(g, "labelfontname"); 00850 E_labelfontcolor = agfindedgeattr(g, "labelfontcolor"); 00851 E_labeldistance = agfindedgeattr(g, "labeldistance"); 00852 E_labelangle = agfindedgeattr(g, "labelangle"); 00853 /* end vladimir */ 00854 E_minlen = agfindedgeattr(g, "minlen"); 00855 E_showboxes = agfindedgeattr(g, "showboxes"); 00856 E_style = agfindedgeattr(g, "style"); 00857 E_decorate = agfindedgeattr(g, "decorate"); 00858 E_arrowsz = agfindedgeattr(g, "arrowsize"); 00859 E_constr = agfindedgeattr(g, "constraint"); 00860 E_layer = agfindedgeattr(g, "layer"); 00861 E_comment = agfindedgeattr(g, "comment"); 00862 E_tailclip = agfindedgeattr(g, "tailclip"); 00863 E_headclip = agfindedgeattr(g, "headclip"); 00864 E_penwidth = agfindedgeattr(g, "penwidth"); 00865 00866 /* background */ 00867 GD_drawing(g)->xdots = init_xdot (g); 00868 00869 /* initialize id, if any */ 00870 00871 if ((p = agget(g, "id")) && *p) 00872 GD_drawing(g)->id = strdup_and_subst_obj(p, g); 00873 } 00874 00875 void graph_cleanup(graph_t *g) 00876 { 00877 if (GD_drawing(g)->xdots) 00878 freeXDot ((xdot*)GD_drawing(g)->xdots); 00879 if (GD_drawing(g)->id) 00880 free (GD_drawing(g)->id); 00881 free(GD_drawing(g)); 00882 GD_drawing(g) = NULL; 00883 free_label(GD_label(g)); 00884 #ifdef WITH_CGRAPH 00885 //FIX HERE , STILL SHALLOW 00886 //memset(&(g->u), 0, sizeof(Agraphinfo_t)); 00887 agclean(g, AGRAPH,"Agraphinfo_t"); 00888 #else 00889 memset(&(g->u), 0, sizeof(Agraphinfo_t)); 00890 #endif 00891 } 00892 00893 /* charsetToStr: 00894 * Given an internal charset value, return a canonical string 00895 * representation. 00896 */ 00897 char* 00898 charsetToStr (int c) 00899 { 00900 char* s; 00901 00902 switch (c) { 00903 case CHAR_UTF8 : 00904 s = "UTF-8"; 00905 break; 00906 case CHAR_LATIN1 : 00907 s = "ISO-8859-1"; 00908 break; 00909 case CHAR_BIG5 : 00910 s = "BIG-5"; 00911 break; 00912 default : 00913 agerr(AGERR, "Unsupported charset value %d\n", c); 00914 s = "UTF-8"; 00915 break; 00916 } 00917 return s; 00918 } 00919 00920 /* do_graph_label: 00921 * Set characteristics of graph label if it exists. 00922 * 00923 */ 00924 void do_graph_label(graph_t * sg) 00925 { 00926 char *str, *pos, *just; 00927 int pos_ix; 00928 00929 /* it would be nice to allow multiple graph labels in the future */ 00930 if ((str = agget(sg, "label")) && (*str != '\0')) { 00931 char pos_flag; 00932 pointf dimen; 00933 00934 GD_has_labels(sg->root) |= GRAPH_LABEL; 00935 00936 GD_label(sg) = make_label((void*)sg, str, (aghtmlstr(str) ? LT_HTML : LT_NONE), 00937 late_double(sg, agfindgraphattr(sg, "fontsize"), 00938 DEFAULT_FONTSIZE, MIN_FONTSIZE), 00939 late_nnstring(sg, agfindgraphattr(sg, "fontname"), 00940 DEFAULT_FONTNAME), 00941 late_nnstring(sg, agfindgraphattr(sg, "fontcolor"), 00942 DEFAULT_COLOR)); 00943 00944 /* set label position */ 00945 pos = agget(sg, "labelloc"); 00946 if (sg != agroot(sg)) { 00947 if (pos && (pos[0] == 'b')) 00948 pos_flag = LABEL_AT_BOTTOM; 00949 else 00950 pos_flag = LABEL_AT_TOP; 00951 } else { 00952 if (pos && (pos[0] == 't')) 00953 pos_flag = LABEL_AT_TOP; 00954 else 00955 pos_flag = LABEL_AT_BOTTOM; 00956 } 00957 just = agget(sg, "labeljust"); 00958 if (just) { 00959 if (just[0] == 'l') 00960 pos_flag |= LABEL_AT_LEFT; 00961 else if (just[0] == 'r') 00962 pos_flag |= LABEL_AT_RIGHT; 00963 } 00964 GD_label_pos(sg) = pos_flag; 00965 00966 if (sg == agroot(sg)) 00967 return; 00968 00969 /* Set border information for cluster labels to allow space 00970 */ 00971 dimen = GD_label(sg)->dimen; 00972 PAD(dimen); 00973 if (!GD_flip(agroot(sg))) { 00974 if (GD_label_pos(sg) & LABEL_AT_TOP) 00975 pos_ix = TOP_IX; 00976 else 00977 pos_ix = BOTTOM_IX; 00978 GD_border(sg)[pos_ix] = dimen; 00979 } else { 00980 /* when rotated, the labels will be restored to TOP or BOTTOM */ 00981 if (GD_label_pos(sg) & LABEL_AT_TOP) 00982 pos_ix = RIGHT_IX; 00983 else 00984 pos_ix = LEFT_IX; 00985 GD_border(sg)[pos_ix].x = dimen.y; 00986 GD_border(sg)[pos_ix].y = dimen.x; 00987 } 00988 } 00989 }
1.7.5