static char *nameOf(void *obj, agxbuf * xb) { Agedge_t *ep; switch (agobjkind(obj)) { #ifndef WITH_CGRAPH case AGGRAPH: #else case AGRAPH: #endif agxbput(xb, agnameof(((Agraph_t *) obj))); break; case AGNODE: agxbput(xb, agnameof(((Agnode_t *) obj))); break; case AGEDGE: ep = (Agedge_t *) obj; agxbput(xb, agnameof(agtail(ep))); agxbput(xb, agnameof(aghead(ep))); if (agisdirected(agraphof(aghead(ep)))) agxbput(xb, "->"); else agxbput(xb, "--"); break; } return agxbuse(xb); }
/* setAttr: * Sets object's name attribute to the given value. * Creates the attribute if not already set. */ static Agsym_t *setAttr(graph_t * g, void *obj, char *name, char *value, Agsym_t * ap) { if (ap == NULL) { switch (agobjkind(obj)) { case AGGRAPH: ap = agraphattr(g, name, ""); break; case AGNODE: ap = agnodeattr(g, name, ""); break; case AGEDGE: ap = agedgeattr(g, name, ""); break; } } agxset(obj, ap->index, value); return ap; }
/* setAttr: * Sets object's name attribute to the given value. * Creates the attribute if not already set. */ Agsym_t *setAttr(graph_t * g, void *obj, char *name, char *value, Agsym_t * ap) { if (ap == NULL) { switch (agobjkind(obj)) { case AGRAPH: ap = agattr(g, AGRAPH,name, ""); break; case AGNODE: ap = agattr(g,AGNODE, name, ""); break; case AGEDGE: ap = agattr(g,AGEDGE, name, ""); break; } } agxset(obj, ap, value); return ap; }
static int repkeycmp(Dt_t *d, void *arg0, void *arg1, Dtdisc_t *disc) { void *key0 = ((repkey_t*)arg0)->key; void *key1 = ((repkey_t*)arg1)->key; int rv; switch(agobjkind(key0)) { case AGNODE: rv = ((Agnode_t*)key0)->id - ((Agnode_t*)key1)->id; break; case AGEDGE: rv = ((Agedge_t*)key0)->id - ((Agedge_t*)key1)->id; break; case AGRAPH: /* in libgraph we don't seem to have graph ids, so use pointer */ rv = (unsigned long)key0 - (unsigned long) key1; break; default: rv = 0; } return rv; }
static char *nameOf(void *obj, agxbuf * xb) { Agedge_t *ep; switch (agobjkind(obj)) { case AGGRAPH: agxbput(xb, ((Agraph_t *) obj)->name); break; case AGNODE: agxbput(xb, ((Agnode_t *) obj)->name); break; case AGEDGE: ep = (Agedge_t *) obj; agxbput(xb, ep->tail->name); agxbput(xb, ep->head->name); if (AG_IS_DIRECTED(ep->tail->graph)) agxbput(xb, "->"); else agxbput(xb, "--"); break; } return agxbuse(xb); }
/* strdup_and_subst_obj0: * Replace various escape sequences with the name of the associated * graph object. A double backslash \\ can be used to avoid a replacement. * If escBackslash is true, convert \\ to \; else leave alone. All other dyads * of the form \. are passed through unchanged. */ static char *strdup_and_subst_obj0 (char *str, void *obj, int escBackslash) { char c, *s, *p, *t, *newstr; char *tp_str = "", *hp_str = ""; char *g_str = "\\G", *n_str = "\\N", *e_str = "\\E", *h_str = "\\H", *t_str = "\\T", *l_str = "\\L"; int g_len = 2, n_len = 2, e_len = 2, h_len = 2, t_len = 2, l_len = 2, tp_len = 0, hp_len = 0; int newlen = 0; int isEdge = 0; textlabel_t *tl; port pt; /* prepare substitution strings */ switch (agobjkind(obj)) { case AGRAPH: g_str = agnameof((graph_t *)obj); g_len = strlen(g_str); tl = GD_label((graph_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } break; case AGNODE: g_str = agnameof(agraphof((node_t *)obj)); g_len = strlen(g_str); n_str = agnameof((node_t *)obj); n_len = strlen(n_str); tl = ND_label((node_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } break; case AGEDGE: isEdge = 1; g_str = agnameof(agroot(agraphof(agtail(((edge_t *)obj))))); g_len = strlen(g_str); t_str = agnameof(agtail(((edge_t *)obj))); t_len = strlen(t_str); pt = ED_tail_port((edge_t *)obj); if ((tp_str = pt.name)) tp_len = strlen(tp_str); h_str = agnameof(aghead(((edge_t *)obj))); h_len = strlen(h_str); pt = ED_head_port((edge_t *)obj); if ((hp_str = pt.name)) hp_len = strlen(hp_str); h_len = strlen(h_str); tl = ED_label((edge_t *)obj); if (tl) { l_str = tl->text; if (str) l_len = strlen(l_str); } if (agisdirected(agroot(agraphof(agtail(((edge_t*)obj)))))) e_str = "->"; else e_str = "--"; e_len = t_len + (tp_len?tp_len+1:0) + 2 + h_len + (hp_len?hp_len+1:0); break; } /* two passes over str. * * first pass prepares substitution strings and computes * total length for newstring required from malloc. */ for (s = str; (c = *s++);) { if (c == '\\') { switch (c = *s++) { case 'G': newlen += g_len; break; case 'N': newlen += n_len; break; case 'E': newlen += e_len; break; case 'H': newlen += h_len; break; case 'T': newlen += t_len; break; case 'L': newlen += l_len; break; case '\\': if (escBackslash) { newlen += 1; break; } /* Fall through */ default: /* leave other escape sequences unmodified, e.g. \n \l \r */ newlen += 2; } } else { newlen++; } } /* allocate new string */ newstr = gmalloc(newlen + 1); /* second pass over str assembles new string */ for (s = str, p = newstr; (c = *s++);) { if (c == '\\') { switch (c = *s++) { case 'G': for (t = g_str; (*p = *t++); p++); break; case 'N': for (t = n_str; (*p = *t++); p++); break; case 'E': if (isEdge) { for (t = t_str; (*p = *t++); p++); if (tp_len) { *p++ = ':'; for (t = tp_str; (*p = *t++); p++); } for (t = e_str; (*p = *t++); p++); for (t = h_str; (*p = *t++); p++); if (hp_len) { *p++ = ':'; for (t = hp_str; (*p = *t++); p++); } } break; case 'T': for (t = t_str; (*p = *t++); p++); break; case 'H': for (t = h_str; (*p = *t++); p++); break; case 'L': for (t = l_str; (*p = *t++); p++); break; case '\\': if (escBackslash) { *p++ = '\\'; break; } /* Fall through */ default: /* leave other escape sequences unmodified, e.g. \n \l \r */ *p++ = '\\'; *p++ = c; break; } } else { *p++ = c; } } *p++ = '\0'; return newstr; }
/* make_label: * Assume str is freshly allocated for this instance, so it * can be freed in free_label. */ textlabel_t *make_label(void *obj, char *str, int kind, double fontsize, char *fontname, char *fontcolor) { textlabel_t *rv = NEW(textlabel_t); graph_t *g = NULL, *sg = NULL; node_t *n = NULL; edge_t *e = NULL; char *s; switch (agobjkind(obj)) { case AGRAPH: sg = (graph_t*)obj; g = sg->root; break; case AGNODE: n = (node_t*)obj; g = agroot(agraphof(n)); break; case AGEDGE: e = (edge_t*)obj; g = agroot(agraphof(aghead(e))); break; } rv->fontname = fontname; rv->fontcolor = fontcolor; rv->fontsize = fontsize; rv->charset = GD_charset(g); if (kind & LT_RECD) { rv->text = strdup(str); if (kind & LT_HTML) { rv->html = TRUE; } } else if (kind == LT_HTML) { rv->text = strdup(str); rv->html = TRUE; if (make_html_label(obj, rv)) { switch (agobjkind(obj)) { case AGRAPH: agerr(AGPREV, "in label of graph %s\n",agnameof(sg)); break; case AGNODE: agerr(AGPREV, "in label of node %s\n", agnameof(n)); break; case AGEDGE: agerr(AGPREV, "in label of edge %s %s %s\n", agnameof(agtail(e)), agisdirected(g)?"->":"--", agnameof(aghead(e))); break; } } } else { assert(kind == LT_NONE); /* This call just processes the graph object based escape sequences. The formatting escape * sequences (\n, \l, \r) are processed in make_simple_label. That call also replaces \\ with \. */ rv->text = strdup_and_subst_obj0(str, obj, 0); switch (rv->charset) { case CHAR_LATIN1: s = latin1ToUTF8(rv->text); break; default: /* UTF8 */ s = htmlEntityUTF8(rv->text, g); break; } free(rv->text); rv->text = s; make_simple_label(GD_gvc(g), rv); } return rv; }
/* make_html_label: * Return non-zero if problem parsing HTML. In this case, use object name. */ int make_html_label(graph_t *g, textlabel_t * lp, void *obj) { int rv; int wd2, ht2; box box; htmllabel_t *lbl; htmlenv_t env; env.obj = obj; switch (agobjkind(obj)) { case AGGRAPH: env.g = ((Agraph_t *) obj)->root; break; case AGNODE: env.g = ((Agnode_t *) obj)->graph; break; case AGEDGE: env.g = ((Agedge_t *) obj)->head->graph; break; } env.finfo.size = lp->fontsize; env.finfo.name = lp->fontname; env.finfo.color = lp->fontcolor; lbl = parseHTML(lp->text, &rv, GD_charset(env.g)); if (!lbl) { /* Parse of label failed; revert to simple text label */ agxbuf xb; unsigned char buf[SMALLBUF]; agxbinit(&xb, SMALLBUF, buf); lp->html = FALSE; lp->text = strdup(nameOf(obj, &xb)); size_label(env.g, lp); agxbfree(&xb); return rv; } if (lbl->kind == HTML_TBL) { lbl->u.tbl->data.pencolor = getPenColor(obj); rv |= size_html_tbl(g, lbl->u.tbl, NULL, &env); wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2; ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2; box = boxof(-wd2, -ht2, wd2, ht2); pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT); lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } else { rv |= size_html_txt(g, lbl->u.txt, &env); wd2 = (lbl->u.txt->box.UR.x + 1) / 2; ht2 = (lbl->u.txt->box.UR.y + 1) / 2; box = boxof(-wd2, -ht2, wd2, ht2); lbl->u.txt->box = box; lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } lp->u.html = lbl; /* If the label is a table, replace label text because this may * be used for the title and alt fields in image maps. */ if (lbl->kind == HTML_TBL) { free (lp->text); lp->text = strdup ("<TABLE>"); } return rv; }
/* make_html_label: * Return non-zero if problem parsing HTML. In this case, use object name. */ int make_html_label(void *obj, textlabel_t * lp) { int rv; double wd2, ht2; boxf box; graph_t *g; htmllabel_t *lbl; htmlenv_t env; char *s; env.obj = obj; switch (agobjkind(obj)) { #ifdef WITH_CGRAPH case AGRAPH: #else case AGGRAPH: #endif env.g = ((Agraph_t *) obj)->root; break; case AGNODE: env.g = agraphof(((Agnode_t *) obj)); break; case AGEDGE: env.g = agraphof(aghead (((Agedge_t *) obj))); break; } g = env.g->root; env.finfo.size = lp->fontsize; env.finfo.name = lp->fontname; env.finfo.color = lp->fontcolor; lbl = parseHTML(lp->text, &rv, GD_charset(env.g)); if (!lbl) { /* Parse of label failed; revert to simple text label */ agxbuf xb; unsigned char buf[SMALLBUF]; agxbinit(&xb, SMALLBUF, buf); lp->html = FALSE; lp->text = strdup(nameOf(obj, &xb)); switch (lp->charset) { case CHAR_LATIN1: s = latin1ToUTF8(lp->text); break; default: /* UTF8 */ s = htmlEntityUTF8(lp->text, env.g); break; } free(lp->text); lp->text = s; make_simple_label(g, lp); agxbfree(&xb); return rv; } if (lbl->kind == HTML_TBL) { if (! lbl->u.tbl->data.pencolor && getPenColor(obj)) lbl->u.tbl->data.pencolor = strdup(getPenColor(obj)); rv |= size_html_tbl(g, lbl->u.tbl, NULL, &env); wd2 = (lbl->u.tbl->data.box.UR.x + 1) / 2; ht2 = (lbl->u.tbl->data.box.UR.y + 1) / 2; box = boxfof(-wd2, -ht2, wd2, ht2); pos_html_tbl(lbl->u.tbl, box, BOTTOM | RIGHT | TOP | LEFT); lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } else { rv |= size_html_txt(g, lbl->u.txt, &env); wd2 = (lbl->u.txt->box.UR.x + 1) / 2; ht2 = (lbl->u.txt->box.UR.y + 1) / 2; box = boxfof(-wd2, -ht2, wd2, ht2); lbl->u.txt->box = box; lp->dimen.x = box.UR.x - box.LL.x; lp->dimen.y = box.UR.y - box.LL.y; } lp->u.html = lbl; /* If the label is a table, replace label text because this may * be used for the title and alt fields in image maps. */ if (lbl->kind == HTML_TBL) { free (lp->text); lp->text = strdup ("<TABLE>"); } return rv; }