Graphviz  2.31.20130618.0446
lib/common/input.c
Go to the documentation of this file.
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 }