27 #endif // HAVE_UNISTD_H
79 if (!p || p[0] ==
'\0')
81 rv = strtol (p, &endp, 10);
82 if (p == endp)
return def;
83 if (rv < low)
return low;
96 if (!p || p[0] ==
'\0')
98 rv = strtod (p, &endp);
99 if (p == endp)
return def;
100 if (rv < low)
return low;
132 if (!rv || (rv[0] ==
'\0'))
227 for (j = 0; j <= degree; j++) {
232 for (i = 1; i <= degree; i++) {
233 for (j = 0; j <= degree - i; j++) {
235 (1.0 - t) * Vtemp[i - 1][j].x + t * Vtemp[i - 1][j + 1].x;
237 (1.0 - t) * Vtemp[i - 1][j].y + t * Vtemp[i - 1][j + 1].y;
242 for (j = 0; j <= degree; j++)
243 Left[j] = Vtemp[j][0];
245 for (j = 0; j <= degree; j++)
246 Right[j] = Vtemp[degree - j][j];
248 return (Vtemp[degree][0]);
270 static void cleanup(
void)
284 static int bsize = 0;
291 if (bsize - len < BUFSIZ) {
295 lp = fgets(buf + len, bsize - len, fp);
299 }
while (buf[len - 1] !=
'\n');
339 static char** mkDirlist (
const char* list,
int* maxdirlen)
342 char*
s = strdup (list);
348 dirs =
ALLOC (cnt+2,dirs,
char*);
350 maxlen =
MAX(maxlen, strlen (dir));
357 static char* findPath (
char** dirs,
int maxdirlen,
const char*
str)
359 static char *safefilename =
NULL;
366 safefilename = realloc(safefilename, (maxdirlen + strlen(str) + 2));
368 for (dp = dirs; *dp; dp++) {
369 sprintf (safefilename,
"%s%s%s", *dp,
DIRSEP, str);
370 if (access (safefilename, R_OK) == 0)
378 static boolean onetime =
TRUE;
379 static char *pathlist =
NULL;
380 static int maxdirlen;
384 if (!filename || !filename[0])
396 "file loading is disabled because the environment contains SERVER_NAME=\"%s\"\n"
397 "and the GV_FILE_PATH variable is unset or empty.\n",
409 if ((p = strrchr(str,
'/')))
411 if ((p = strrchr(str,
'\\')))
413 if ((p = strrchr(str,
':')))
416 if (onetime && str != filename) {
417 agerr(
AGWARN,
"Path provided to file: \"%s\" has been ignored"
418 " because files are only permitted to be loaded from the directories in \"%s\""
419 " when running in an http server.\n", filename,
Gvfilepath);
423 return findPath (dirs, maxdirlen, str);
433 if (pathlist && *pathlist)
434 dirs = mkDirlist (pathlist, &maxdirlen);
437 if ((*filename ==
DIRSEP[0]) || !dirs)
440 return findPath (dirs, maxdirlen, filename);
448 for (i = 0; (q = name[i]) != 0; i++)
449 if (p &&
streq(p, q))
456 if (!p || (*p ==
'\0'))
479 int i, j, k, besti, bestj;
480 double bestdist2, d2, dlow2, dhigh2;
487 for (i = 0; i < spl->
size; i++) {
489 for (j = 0; j < bz.
size; j++) {
495 if ((bestj == -1) || (d2 < bestdist2)) {
503 bz = spl->
list[besti];
508 if (bestj == bz.
size-1)
511 for (k = 0; k < 4; k++) {
512 c[k].
x = bz.
list[j + k].
x;
513 c[k].
y = bz.
list[j + k].
y;
517 dlow2 =
DIST2(c[0], pt);
518 dhigh2 =
DIST2(c[3], pt);
520 t = (low + high) / 2.0;
522 if (fabs(dlow2 - dhigh2) < 1.0)
524 if (fabs(high - low) < .00001)
526 if (dlow2 < dhigh2) {
528 dhigh2 =
DIST2(pt2, pt);
531 dlow2 =
DIST2(pt2, pt);
540 double low, high, d, t;
553 for (i = 0; i < spl->
size; i++) {
561 if (y > bz.
list[0].
y)
566 for (i = 0; i < bz.
size; i += 3) {
567 for (j = 0; j < 3; j++) {
568 if ((bz.
list[i + j].
y <= y) && (y <= bz.
list[i + j + 1].
y))
570 if ((bz.
list[i + j].
y >= y) && (y >= bz.
list[i + j + 1].
y))
577 for (j = 0; j < 4; j++) {
578 c[j].
x = bz.
list[i + j].
x;
579 c[j].
y = bz.
list[i + j].
y;
581 if ((j > 0) && (c[j].y > c[j - 1].y))
587 t = (low + high) / 2.0;
667 if (!fi->
fontname) initFontEdgeAttr(e, fi);
685 if (str && str[0]) rv = !
mapbool(str);
726 initFontEdgeAttr(e, &fi);
736 initFontEdgeAttr(e, &fi);
745 initFontLabelEdgeAttr(e, &fi, &lfi);
752 initFontLabelEdgeAttr(e, &fi, &lfi);
787 double width, height;
799 min = p.
x - width / 2.;
800 max = p.
x + width / 2.;
806 min = p.
y - height / 2.;
807 max = p.
y + height / 2.;
823 int i, sides = poly->
sides;
828 bb.
LL = bb.
UR = verts[0];
829 for (i = 1; i < sides; i++) {
862 bb.
LL = pointfof(0, 0);
863 bb.
UR = pointfof(0, 0);
873 b.
LL = sub_pointf(ptf, s2);
874 b.
UR = add_pointf(ptf, s2);
883 for (i = 0; i <
ED_spl(e)->size; i++) {
885 ptf =
ED_spl(e)->list[i].list[j];
958 sprintf(num,
"%d", idx++);
988 static int cmpItem(
Dt_t * d,
void *p1[],
void *p2[],
Dtdisc_t * disc)
995 else if (p1[0] > p2[0])
997 else if (p1[1] < p2[1])
999 else if (p1[1] > p2[1])
1012 newp->
p[0] = objp->
p[0];
1013 newp->
p[1] = objp->
p[1];
1029 sizeof(2 *
sizeof(
void *)),
1030 offsetof(
item, link),
1055 static void insertEdge(
Dt_t * map,
void *t,
void *h,
edge_t * e)
1101 #define MAPC(n) (strncmp(agnameof(n),"cluster",7)?NULL:findCluster(cmap,agnameof(n)))
1125 ip = mapEdge(map, e);
1127 cloneEdge(e, ip->
t, ip->
h);
1134 agerr(
AGWARN,
"tail cluster %s inside head cluster %s\n",
1139 agerr(
AGWARN,
"head cluster %s inside tail cluster %s\n",
1143 cn = clustNode(t, tg, xb, clg);
1144 cn1 = clustNode(h, hg, xb, clg);
1145 ce = cloneEdge(e, cn, cn1);
1146 insertEdge(map, t, h, ce);
1149 agerr(
AGWARN,
"tail node %s inside head cluster %s\n",
1153 cn = clustNode(h, hg, xb, clg);
1154 ce = cloneEdge(e, t, cn);
1155 insertEdge(map, t, h, ce);
1163 cn = clustNode(t, tg, xb, clg);
1164 ce = cloneEdge(e, cn, h);
1165 insertEdge(map, t, h, ce);
1194 int num_cl_edges = 0;
1205 clg =
agsubg(g,
"__clusternodes",1);
1211 num_cl_edges += checkCompound(e, clg, &xb, map, cmap);
1272 ntail = mapN(t, clg);
1273 nhead = mapN(h, clg);
1274 ce = cloneEdge(e, ntail, nhead);
1302 int ecnt = num_clust_edges(g);
1306 clg =
agsubg(g,
"__clusternodes",1);
1316 for (i = 0; i < ecnt; i++)
1317 undoCompound(elist[i], clg);
1319 for (n =
agfstnode(clg); n; n = nextn) {
1337 a =
agattr(g,obj_kind,name,def);
1341 static int comp_entities(
const void *e1,
const void *e2) {
1342 return strcmp(((
struct entities_s *)e1)->name, ((
struct entities_s *)e2)->name);
1354 char* endp = strchr (t,
';');
1355 struct entities_s key, *res;
1360 if (!endp)
return t;
1361 if (((len = endp-t) >
MAXENTLEN) || (len < 2))
return t;
1362 strncpy (buf, t, len);
1366 sizeof(entities[0]), comp_entities);
1368 sprintf (buf,
"%d", res->value);
1384 htmlEntity (
char** s)
1387 struct entities_s key, *res;
1389 unsigned char* str = *(
unsigned char**)s;
1396 if (byte ==
'x' || byte ==
'X') {
1397 for (i = 2; i < 8; i++) {
1399 if (byte >=
'A' && byte <=
'F')
1400 byte = byte -
'A' + 10;
1401 else if (byte >=
'a' && byte <=
'f')
1402 byte = byte -
'a' + 10;
1403 else if (byte >=
'0' && byte <=
'9')
1407 n = (n * 16) + byte;
1411 for (i = 1; i < 8; i++) {
1413 if (byte >=
'0' && byte <=
'9')
1414 n = (n * 10) + (byte -
'0');
1427 key.name = p = entity_name_buf;
1430 if (byte ==
'\0')
break;
1434 sizeof(entities[0]), *comp_entities);
1448 static unsigned char
1449 cvtAndAppend (
unsigned char c,
agxbuf* xb)
1476 static boolean warned;
1479 unsigned char buf[BUFSIZ];
1493 while ((c = *(
unsigned char*)s++)) {
1511 agerr(
AGWARN,
"UTF8 codes > 4 bytes are not currently supported (graph %s) - treated as Latin-1. Perhaps \"-Gcharset=latin1\" is needed?\n",
agnameof(g));
1514 c = cvtAndAppend (c, &xb);
1517 if (uc == 0 && c ==
'&') {
1520 v = htmlEntity (&s);
1524 else if (v < 0x07FF) {
1526 c = (v & 0x3F) | 0x80;
1530 agxbputc(&xb, ((v >> 6) & 0x3F) | 0x80);
1531 c = (v & 0x3F) | 0x80;
1536 for (ui = 0; ui < uc; ++ui)
1537 if ((*s & 0xC0) == 0x80) {
1539 c = *(
unsigned char*)s++;
1543 agerr(
AGWARN,
"Invalid %d-byte UTF8 found in input of graph %s - treated as Latin-1. Perhaps \"-Gcharset=latin1\" is needed?\n", uc + 1,
agnameof(g));
1546 c = cvtAndAppend (c, &xb);
1565 unsigned char buf[BUFSIZ];
1573 while ((v = *(
unsigned char*)s++)) {
1575 v = htmlEntity (&s);
1580 else if (v < 0x07FF) {
1586 agxbputc(&xb, ((v >> 6) & 0x3F) | 0x80);
1605 unsigned char buf[BUFSIZ];
1611 while ((c = *(
unsigned char*)s++)) {
1615 outc = (c & 0x03) << 6;
1616 c = *(
unsigned char*)s++;
1617 outc = outc | (c & 0x3F);
1640 return ND_shape(n)->fns->insidefn(&ictxt, p);
1650 bb.
LL = sub_pointf(lp->
pos, s);
1651 bb.
UR = add_pointf(lp->
pos, s);
1655 static boolean overlap_arrow(
pointf p,
pointf u,
double scale,
int flag,
boxf b)
1664 static boolean overlap_bezier(
bezier bz,
boxf b)
1671 for (i = 1; i < bz.
size; i++) {
1680 if (overlap_arrow(bz.
sp, bz.
list[0], 1, bz.
sflag, b))
1697 if (spl && boxf_overlap(spl->
bb, b))
1698 for (i = 0; i < spl->
size; i++)
1699 if (overlap_bezier(spl->
list[i], b))
1716 if (!s || (*s ==
'\0'))
return dflt;
1783 agerr(
AGWARN,
"Unknown \"splines\" value: \"%s\" - ignored\n", s);
1804 char* s =
agget(g,
"splines");
1810 else if (*s ==
'\0') {
1832 int isRadial = flags & 1;
1833 int isRHS = flags & 2;
1836 rx = A[1].
x - A[0].
x;
1837 ry = A[1].
y - A[0].
y;
1838 min.
x = A[0].
x - rx;
1839 max.
x = A[0].
x + rx;
1840 min.
y = A[0].
y - ry;
1841 max.
y = A[0].
y + ry;
1844 min.
x = max.
x = A[0].
x;
1845 min.
y = max.
y = A[0].
y;
1846 for (i = 0; i < n; i++){
1847 min.
x =
MIN(A[i].x,min.
x);
1848 min.
y =
MIN(A[i].y,min.
y);
1849 max.
x =
MAX(A[i].x,max.
x);
1850 max.
y =
MAX(A[i].y,max.
y);
1853 center.
x = min.
x + (max.
x - min.
x)/2;
1854 center.
y = min.
y + (max.
y - min.
y)/2;
1856 double inner_r, outer_r;
1857 outer_r = sqrt((center.
x - min.
x)*(center.
x - min.
x) +
1858 (center.
y - min.
y)*(center.
y - min.
y));
1859 inner_r = outer_r /4.;
1871 double half_x = max.
x - center.
x;
1872 double half_y = max.
y - center.
y;
1873 double sina = sin(angle);
1874 double cosa = cos(angle);
1876 G[0].
y = center.
y - half_y * sina;
1877 G[1].
y = center.
y + half_y * sina;
1880 G[0].
y = -center.
y + (max.
y - center.
y) * sin(angle);
1881 G[1].
y = -center.
y - (center.
y - min.
y) * sin(angle);
1883 G[0].
x = center.
x - half_x * cosa;
1884 G[1].
x = center.
x + half_x * cosa;
1888 #ifndef WIN32_STATIC
1889 #ifndef HAVE_STRCASECMP
1898 while ((*s1 !=
'\0')
1899 && (tolower(*(
unsigned char *) s1) ==
1900 tolower(*(
unsigned char *) s2))) {
1905 return tolower(*(
unsigned char *) s1) - tolower(*(
unsigned char *) s2);
1911 #ifndef WIN32_STATIC
1912 #ifndef HAVE_STRNCASECMP
1922 && (tolower(*(
unsigned char *) s1) ==
1923 tolower(*(
unsigned char *) s2))) {
1924 if (n == 0 || *s1 ==
'\0' || *s2 ==
'\0')
1930 return tolower(*(
unsigned char *) s1) - tolower(*(
unsigned char *) s2);
1939 for (i = 0; i <
ED_spl(e)->size; i++)
1940 free(
ED_spl(e)->list[i].list);
1994 if((fp = fopen(
"fix-fc.exe",
"r")) ==
NULL)
1997 if (!system (
"fix-fc.exe")) {
1998 system (
"del fix-fc.exe");
2004 #ifndef HAVE_DRAND48
2047 agerr(
AGWARN,
"Two clusters named %s - the second will be ignored\n", s);
void s1(graph_t *, node_t *)
int(* Dtcompar_f)(Dt_t *, void *, void *, Dtdisc_t *)
unsigned int(* Dthash_f)(Dt_t *, void *, Dtdisc_t *)
void free_label(textlabel_t *p)
EXTERN char * Gvimagepath
CGRAPH_API int agobjkind(void *)
EXTERN Agsym_t * N_showboxes
CGRAPH_API Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
EXTERN Agsym_t * E_labelfontcolor
CDT_API int dtclose(Dt_t *)
attrsym_t * safe_dcl(graph_t *g, int obj_kind, char *name, char *def)
#define DEFAULT_NODEWIDTH
Agsym_t * agattr(Agraph_t *g, int kind, char *name, char *value)
void *(* Dtmake_f)(Dt_t *, void *, Dtdisc_t *)
char * latin1ToUTF8(char *s)
void * grealloc(void *ptr, size_t size)
Agraphinfo_t * ginf(Agraph_t *g)
Agnodeinfo_t * ninf(Agnode_t *n)
Dt_t * mkClustMap(Agraph_t *g)
CGRAPH_API int aghtmlstr(char *)
Agsym_t * setAttr(graph_t *g, void *obj, char *name, char *value, Agsym_t *ap)
char * htmlEntityUTF8(char *s, graph_t *g)
EXTERN Agsym_t * E_tailclip
boolean overlap_edge(edge_t *e, boxf b)
Agsym_t * agnxtattr(Agraph_t *g, int kind, Agsym_t *attr)
char * late_nnstring(void *obj, attrsym_t *attr, char *def)
EXTERN Agsym_t * N_fontname
EXTERN Agsym_t * N_fontcolor
shape_kind shapeOf(node_t *)
int agxset(void *obj, Agsym_t *sym, char *value)
CDT_API Dtmethod_t * Dtoset
EXTERN Agsym_t * N_fontsize
#define ALLOC(size, ptr, type)
EXTERN char * HTTPServerEnVar
EXTERN Agsym_t * N_height
void undoClusterEdges(graph_t *g)
#define DEFAULT_NODEHEIGHT
EXTERN Agsym_t * E_labelfontname
#define SET_CLUST_NODE(n)
size_t agxbput(agxbuf *xb, const char *s)
EXTERN Agsym_t * E_headlabel
void common_init_node(node_t *n)
EXTERN Agsym_t * E_fontcolor
void UF_remove(node_t *u, node_t *v)
CGRAPH_API int agdelete(Agraph_t *g, void *obj)
EXTERN Agsym_t * E_label_float
int agerr(agerrlevel_t level, const char *fmt,...)
#define ED_label_ontop(e)
void gv_cleanup_edge(Agedge_t *e)
CGRAPH_API int agcontains(Agraph_t *, void *)
CGRAPH_API Agraph_t * agroot(void *obj)
CGRAPH_API Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
void enqueue(nodequeue *q, node_t *n)
void UF_setname(node_t *u, node_t *v)
CDT_API Dt_t * dtopen(Dtdisc_t *, Dtmethod_t *)
char * agget(void *obj, char *name)
node_t * UF_find(node_t *n)
CGRAPH_API Agraph_t * agraphof(void *obj)
int lineToBox(pointf p, pointf q, boxf b)
CGRAPH_API Agnode_t * agtail(Agedge_t *e)
nodequeue * new_queue(int sz)
CGRAPH_API Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
CGRAPH_API Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
EXTERN Agsym_t * E_taillabel
CGRAPH_API Agnode_t * aghead(Agedge_t *e)
EXTERN Agsym_t * E_xlabel
CGRAPH_API int agclose(Agraph_t *g)
int strncasecmp(const char *s1, const char *s2, unsigned int n)
CGRAPH_API char * agnameof(void *)
#define INCH2PS(a_inches)
EXTERN Agsym_t * N_xlabel
char * scanEntity(char *t, agxbuf *xb)
void *(* Dtmemory_f)(Dt_t *, void *, size_t, Dtdisc_t *)
void compute_bb(graph_t *g)
void agxbinit(agxbuf *xb, unsigned int hint, unsigned char *init)
node_t * dequeue(nodequeue *q)
boolean mapBool(char *p, boolean dflt)
CGRAPH_API Agnode_t * agfstnode(Agraph_t *g)
int late_int(void *obj, attrsym_t *attr, int def, int low)
void free_queue(nodequeue *q)
void UF_singleton(node_t *u)
double get_inputscale(graph_t *g)
const char * safefile(const char *filename)
void gv_free_splines(edge_t *e)
pointf Bezier(pointf *V, int degree, double t, pointf *Left, pointf *Right)
Agraph_t * findCluster(Dt_t *map, char *name)
int agcopyattr(void *oldobj, void *newobj)
real cg(Operator Ax, Operator precond, int n, int dim, real *x0, real *rhs, real tol, int maxit, int *flag)
CGRAPH_API int agdelrec(void *obj, char *name)
#define agfindgraphattr(g, a)
char * utf8ToLatin1(char *s)
boxf arrow_bb(pointf p, pointf u, double arrowsize, int flag)
EXTERN Agsym_t * E_fontname
double late_double(void *obj, attrsym_t *attr, double def, double low)
#define ENTITY_NAME_LENGTH_MAX
void gv_cleanup_node(Agnode_t *n)
CGRAPH_API int agnnodes(Agraph_t *g)
int strcasecmp(const char *s1, const char *s2)
int is_a_cluster(Agraph_t *g)
CGRAPH_API Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
void updateBB(graph_t *g, textlabel_t *lp)
EXTERN Agsym_t * E_labelfontsize
int(* Dtevent_f)(Dt_t *, int, void *, Dtdisc_t *)
#define DEFAULT_NODESHAPE
CGRAPH_API void * agbindrec(void *obj, char *name, unsigned int size, int move_to_front)
void(* pf)(char *, void *)
void(* Dtfree_f)(Dt_t *, void *, Dtdisc_t *)
int common_init_edge(edge_t *e)
Agedgeinfo_t * einf(Agedge_t *e)
EXTERN Agsym_t * E_headclip
void setEdgeType(graph_t *g, int dflt)
void gv_nodesize(node_t *n, boolean flip)
#define agfindedge(g, t, h)
boolean overlap_node(node_t *n, boxf b)
int edgeType(char *s, int dflt)
char * late_string(void *obj, attrsym_t *attr, char *def)
#define HAS_CLUST_EDGE(g)
boxf polyBB(polygon_t *poly)
EXTERN double PSinputscale
char * agxget(void *obj, Agsym_t *sym)
EXTERN Agsym_t * E_fontsize
CGRAPH_API Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
boolean overlap_label(textlabel_t *lp, boxf b)
void processClusterEdges(graph_t *g)
int maptoken(char *p, char **name, int *val)
pointf neato_closest(splines *spl, pointf p)
pointf dotneato_closest(splines *spl, pointf pt)
shape_desc * bind_shape(char *name, node_t *)
void agxbfree(agxbuf *xb)
pointf spline_at_y(splines *spl, double y)
node_t * UF_union(node_t *u, node_t *v)
CGRAPH_API Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
boolean late_bool(void *obj, attrsym_t *attr, int def)
void get_gradient_points(pointf *A, pointf *G, int n, float angle, int flags)
textlabel_t * make_label(void *obj, char *str, int kind, double fontsize, char *fontname, char *fontcolor)