/* compare: * Lexicographic ordering of objects. */ int compare(Agobj_t * l, Agobj_t * r) { char lkind, rkind; if (l == NULL) { if (r == NULL) return 0; else return -1; } else if (r == NULL) { return 1; } if (AGID(l) < AGID(r)) return -1; else if (AGID(l) > AGID(r)) return 1; lkind = AGTYPE(l); rkind = AGTYPE(r); if (lkind == 3) lkind = 2; if (rkind == 3) rkind = 2; if (lkind == rkind) return 0; else if (lkind < rkind) return -1; else return 1; }
/* external entry point (this seems to be one of those ineffective * comments censured in books on programming style) */ int agapply(Agraph_t * g, Agobj_t * obj, agobjfn_t fn, void *arg, int preorder) { Agobj_t *subobj; agobjsearchfn_t objsearch; switch (AGTYPE(obj)) { case AGRAPH: objsearch = subgraph_search; break; case AGNODE: objsearch = subnode_search; break; case AGOUTEDGE: case AGINEDGE: objsearch = subedge_search; break; default: agerr(AGERR, "agapply: unknown object type %d\n", AGTYPE(obj)); return FAILURE; break; } if ((subobj = objsearch(g, obj))) { rec_apply(g, subobj, fn, arg, objsearch, preorder); return SUCCESS; } else return FAILURE; }
/* copyAttr: * Copy attributes from src to tgt. Overrides currently * defined values. * FIX: we should probably use the default value of the source * graph when initializing the attribute, rather than "". * NOTE: We do not assume src and tgt have the same kind. */ int copyAttr(Agobj_t * src, Agobj_t * tgt) { Agraph_t *srcg; Agraph_t *tgtg; Agsym_t *sym = 0; Agsym_t *tsym = 0; int skind = AGTYPE(src); int tkind = AGTYPE(tgt); char* val; srcg = agraphof(src); tgtg = agraphof(tgt); while ((sym = agnxtattr(srcg, skind, sym))) { tsym = agattrsym(tgt, sym->name); if (!tsym) tsym = agattr(tgtg, tkind, sym->name, sym->defval); val = agxget(src, sym); if (aghtmlstr (val)) { val = agstrdup_html (tgtg, val); agxset(tgt, tsym, val); agstrfree (tgtg, val); } else agxset(tgt, tsym, val); } return 0; }
/*-------------------------------------------------------------------------*\ * Generic method: type = obj.type(self) * Returns type of a graph object. * Returns the type as string: 'graph', 'node' or 'edge'. * Example: * type = n:type() \*-------------------------------------------------------------------------*/ int get_object_type(lua_State *L) { gr_object_t *ud = toobject(L, 1, NULL, STRICT); lua_pushstring(L, AGTYPE(ud->p.p) == AGGRAPH ? "graph" : AGTYPE(ud->p.p) == AGNODE ? "node" : AGTYPE(ud->p.p) == AGEDGE ? "edge" : "unkown"); return 1; }
Agedge_t *findedge(Agnode_t *t, Agnode_t *h) { if (!t || !h) return NULL; if (AGTYPE(t) == AGRAPH || AGTYPE(h) == AGRAPH) return NULL; return agfindedge(agraphof(t), t, h); }
Agedge_t *edge(Agnode_t *t, Agnode_t *h) { if (!gvc || !t || !h) return NULL; // edges from/to the protonode are not permitted if (AGTYPE(t) == AGRAPH || AGTYPE(h) == AGRAPH) return NULL; return agedge(agraphof(t), t, h, NULL, 1); }
static void set_data(Agobj_t * obj, Agrec_t * data, int mtflock) { Agedge_t *e; obj->data = data; obj->tag.mtflock = mtflock; if ((AGTYPE(obj) == AGINEDGE) || (AGTYPE(obj) == AGOUTEDGE)) { e = agopp((Agedge_t *) obj); AGDATA(e) = data; e->base.tag.mtflock = mtflock; } }
/* deleteObj: * Remove obj from g. * obj may belong to a subgraph of g, so we first must map * obj to its version in g. * If g is null, remove object from root graph. * If obj is a (sub)graph, close it. The g parameter is unused. * Return 0 on success, non-zero on failure. */ int deleteObj(Agraph_t * g, Agobj_t * obj) { gdata *data; if (AGTYPE(obj) == AGRAPH) { g = (Agraph_t *) obj; if (g != agroot(g)) return agclose(g); data = gData(g); if (data->lock & 1) { error(ERROR_WARNING, "Cannot delete locked graph %s", agnameof(g)); data->lock |= 2; return -1; } else return agclose(g); } /* node or edge */ if (!g) g = agroot(agraphof(obj)); if (obj) return agdelete(g, obj); else return -1; }
Agraph_t *graphof(Agedge_t *e) { if (!e) return NULL; if (AGTYPE(e) == AGRAPH) return (Agraph_t*)e; /* graph of protoedge is itself recast */ return agraphof(agtail(e)); }
//------------------------------------------------- char *getv(Agnode_t *n, Agsym_t *a) { if (!n || !a) return NULL; if (AGTYPE(n) == AGRAPH) // protonode return NULL; // FIXME ?? return myagxget(n, a); }
Agraph_t *graphof(Agnode_t *n) { if (!n) return NULL; if (AGTYPE(n) == AGRAPH) return (Agraph_t*)n; /* graph of protonode is itself recast */ return agraphof(n); }
Agnode_t *headof(Agedge_t *e) { if (!e) return NULL; if (AGTYPE(e) == AGRAPH) return NULL; return aghead(e); }
//------------------------------------------------- char *getv(Agedge_t *e, Agsym_t *a) { if (!e || !a) return NULL; if (AGTYPE(e) == AGRAPH) // protoedge return NULL; // FIXME ?? return myagxget(e, a); }
Agnode_t *tailof(Agedge_t *e) { if (!e) return NULL; if (AGTYPE(e) == AGRAPH) return NULL; return agtail(e); }
char *nameof(Agnode_t *n) { if (!n) return NULL; if (AGTYPE(n) == AGRAPH) return NULL; return agnameof(n); }
char *setv(Agedge_t *e, Agsym_t *a, char *val) { if (!e || !a || !val) return NULL; if (AGTYPE(e) == AGRAPH) // protoedge return NULL; // FIXME ?? myagxset(e, a, val); return val; }
char *setv(Agnode_t *n, Agsym_t *a, char *val) { if (!n || !a || !val) return NULL; if (AGTYPE(n) == AGRAPH) // protonode return NULL; // FIXME ?? myagxset(n, a, val); return val; }
/* copyAttr; * Copy attributes from src to tgt. Overrides currently * defined values. * FIX: we should probably use the default value of the source * graph when initializing the attribute, rather than "". * NOTE: We do not assume src and tgt have the same kind. */ int copyAttr(Agobj_t * src, Agobj_t * tgt) { Agraph_t *srcg; Agraph_t *tgtg; Agsym_t *sym = 0; Agsym_t *tsym = 0; int skind = AGTYPE(src); int tkind = AGTYPE(tgt); srcg = agraphof(src); tgtg = agraphof(tgt); while ((sym = agnxtattr(srcg, skind, sym))) { tsym = agattrsym(tgt, sym->name); if (!tsym) tsym = agattr(tgtg, tkind, sym->name, ""); agxset(tgt, tsym, agxget(src, sym)); } return 0; }
static void my_ins(Agobj_t * obj, void *context) { Agnode_t *n; if (AGTYPE(obj) == AGNODE) { n = (Agnode_t *) obj; fprintf(stderr, "%s initialized with label %s\n", agnameof(n), agget(n, "label")); } }
char *obj2cmd (void *obj) { static char buf[32]; switch (AGTYPE(obj)) { case AGRAPH: sprintf(buf,"graph%p",obj); break; case AGNODE: sprintf(buf,"node%p",obj); break; case AGINEDGE: case AGOUTEDGE: sprintf(buf,"edge%p",obj); break; } return buf; }
char *agnameof(void *obj) { Agraph_t *g; char *rv; char buf[32]; /* perform internal lookup first */ g = agraphof(obj); if ((rv = aginternalmapprint(g, AGTYPE(obj), AGID(obj)))) return rv; if (AGDISC(g, id)->print) { if ((rv = AGDISC(g, id)->print(AGCLOS(g, id), AGTYPE(obj), AGID(obj)))) return rv; } if (AGTYPE(obj) != AGEDGE) sprintf(buf, "%c%ld", LOCALNAMEPREFIX, AGID(obj)); else buf[0] = 0; return agstrdup(g, buf); }
char *getv(Agedge_t *e, char *attr) { Agraph_t *g; Agsym_t *a; if (!e || !attr) return NULL; if (AGTYPE(e) == AGRAPH) // protoedge return NULL; // FIXME ?? g = agraphof(agtail(e)); a = agattr(g, AGEDGE, attr, NULL); return myagxget(e, a); }
/* isIn: * Return 1 if object objp is in subgraph gp. */ int isIn(Agraph_t * gp, Agobj_t * objp) { if (!sameG(gp, objp, "isIn", 0)) return 0; switch (AGTYPE(objp)) { case AGRAPH: return (agparent((Agraph_t *) objp) == gp); case AGNODE: return (agidnode(gp, AGID(objp), 0) != 0); default: return (agsubedge(gp, (Agedge_t *) objp, 0) != 0); } }
char *getv(Agnode_t *n, char *attr) { Agraph_t *g; Agsym_t *a; if (!n || !attr) return NULL; if (AGTYPE(n) == AGRAPH) // protonode return NULL; // FIXME ?? g = agroot(agraphof(n)); a = agattr(g, AGNODE, attr, NULL); return myagxget(n, a); }
/* clone: * Create new object of type AGTYPE(obj) with all of its * attributes and substructure. * If obj is an edge, end nodes are cloned if necessary. * If obj is a graph, if g is null, create a clone top-level * graph. Otherwise, create a clone subgraph of g. * Assume obj != NULL. */ Agobj_t *clone(Agraph_t * g, Agobj_t * obj) { Agobj_t *nobj = 0; Agedge_t *e; Agnode_t *h; Agnode_t *t; int kind = AGTYPE(obj); char *name; if ((kind != AGRAPH) && !g) { exerror("NULL graph with non-graph object in clone()"); return 0; } switch (kind) { case AGNODE: /* same as copy node */ name = agnameof(obj); nobj = (Agobj_t *) openNode(g, name); if (nobj) copyAttr(obj, nobj); break; case AGRAPH: name = agnameof(obj); if (g) nobj = (Agobj_t *) openSubg(g, name); else nobj = (Agobj_t *) openG(name, ((Agraph_t *) obj)->desc); if (nobj) { copyAttr(obj, nobj); cloneGraph((Agraph_t *) nobj, (Agraph_t *) obj); } break; case AGINEDGE: case AGOUTEDGE: e = (Agedge_t *) obj; t = (Agnode_t *) clone(g, OBJ(agtail(e))); h = (Agnode_t *) clone(g, OBJ(aghead(e))); name = agnameof (AGMKOUT(e)); nobj = (Agobj_t *) openEdge(g, t, h, name); if (nobj) copyAttr(obj, nobj); break; } return nobj; }
Agedge_t *agnxtedge(Agraph_t * g, Agedge_t * e, Agnode_t * n) { Agedge_t *rv; if (AGTYPE(e) == AGOUTEDGE) { rv = agnxtout(g, e); if (rv == NILedge) { do { rv = !rv ? agfstin(g, n) : agnxtin(g,rv); } while (rv && (rv->node == n)); } } else { do { rv = agnxtin(g, e); /* so that we only see each edge once, */ e = rv; } while (rv && (rv->node == n)); /* ignore loops as in-edges */ } return rv; }
/* * Open a new main graph with the given descriptor (directed, strict, etc.) */ Agraph_t *agopen(char *name, Agdesc_t desc, Agdisc_t * arg_disc) { Agraph_t *g; Agclos_t *clos; unsigned long gid; clos = agclos(arg_disc); g = clos->disc.mem->alloc(clos->state.mem, sizeof(Agraph_t)); AGTYPE(g) = AGRAPH; g->clos = clos; g->desc = desc; g->desc.maingraph = TRUE; g->root = g; g->clos->state.id = g->clos->disc.id->open(g); if (agmapnametoid(g, AGRAPH, name, &gid, TRUE)) AGID(g) = gid; /* else AGID(g) = 0 because we have no alternatives */ return agopen1(g); }
char *setv(Agnode_t *n, char *attr, char *val) { Agraph_t *g; Agsym_t *a; if (!n || !attr || !val) return NULL; if (AGTYPE(n) == AGRAPH) { // protonode g = (Agraph_t*)n; a = agattr(g, AGNODE, attr, val); // create default attribute in psuodo protonode // FIXME? - deal with html in "label" attributes return val; } g = agroot(agraphof(n)); a = agattr(g, AGNODE, attr, NULL); if (!a) a = agnodeattr(g, attr, emptystring); myagxset(n, a, val); return val; }
static void write_attrs(Agobj_t * obj, GVJ_t * job, state_t* sp) { Agraph_t* g = agroot(obj); int type = AGTYPE(obj); char* attrval; Agsym_t* sym = agnxtattr(g, type, NULL); if (!sym) return; for (; sym; sym = agnxtattr(g, type, sym)) { if (!(attrval = agxget(obj, sym))) continue; if ((*attrval == '\0') && !streq(sym->name, "label")) continue; gvputs(job, ",\n"); indent(job, sp->Level); gvprintf(job, "\"%s\": ", stoj(sym->name, sp)); if (sp->doXDot && isXDot(sym->name)) write_xdots(agxget(obj, sym), job, sp); else gvprintf(job, "\"%s\"", stoj(agxget(obj, sym), sp)); } }
char *setv(Agedge_t *e, char *attr, char *val) { Agraph_t *g; Agsym_t *a; if (!e || !attr || !val) return NULL; if (AGTYPE(e) == AGRAPH) { // protoedge g = (Agraph_t*)e; a = agattr(g, AGEDGE, attr, val); // create default attribute in pseudo protoedge // FIXME? - deal with html in "label" attributes return val; } g = agroot(agraphof(agtail(e))); a = agattr(g, AGEDGE, attr, NULL); if (!a) a = agattr(g, AGEDGE, attr, emptystring); myagxset(e, a, val); return val; }