/*-------------------------------------------------------------------------*\ * Metamethod: __eq [boolean] * Compare two nodes. * Example: * n1 == n2 or n1 ~= n2 with metamethods \*-------------------------------------------------------------------------*/ static int gr_equal(lua_State *L) { gr_node_t *ud1 = tonode(L, 1, STRICT); gr_node_t *ud2 = tonode(L, 2, STRICT); lua_pushboolean(L, (AGID(ud1->n) == AGID(ud2->n))); return 1; }
/*-------------------------------------------------------------------------*\ * Method: n.degree(self, what) * Determines degree of a node. * Returns number of in-edges (what='*i'), out-edges (what='*o') or the sum * of all edges (what='*a') to/from/of a node. * Example: * rv, err = n:degree("*i") \*-------------------------------------------------------------------------*/ int gr_degree(lua_State *L) { int count = 0; Agedge_t *e; Agraph_t *g; Agnode_t *n; gr_node_t *ud = tonode(L, 1, STRICT); char *flag = (char *) luaL_optstring(L, 2, "*a"); int indeg = TRUE; int outdeg = TRUE; n = ud->n; g = agroot(ud->n); if (*flag != '*'){ luaL_error(L, "invalid format specifier"); return 0; } switch(*(flag+1)){ case 'i': outdeg = FALSE; break; case 'o': indeg = FALSE; break; } if (indeg){ for (e = agfstin(g, n); e; e = agnxtin(g, e)){ count++; } } if (outdeg){ for (e = agfstout(g, n); e; e = agnxtout(g, e)){ count++; } } lua_pushnumber(L, count); return 1; }
/*-------------------------------------------------------------------------*\ * Property: name [string] * Provides the name of a node. * Example: * name = g.name \*-------------------------------------------------------------------------*/ static int gr_nameof(lua_State *L) { gr_node_t *ud = tonode(L, 1, STRICT); if (ud->status != ALIVE){ luaL_error(L, "deleted"); return 0; } lua_pushstring(L, agnameof(ud->n)); return 1; }
/*-------------------------------------------------------------------------*\ * Property: n.graph * Determines the graph to which of a node belongs. * Returns graph userdata. * Example: * rv = n.graph \*-------------------------------------------------------------------------*/ int gr_graphof(lua_State *L) { gr_node_t *ud = tonode(L, 1, STRICT); Agraph_t *g = agraphof(ud->n); if (g == NULL){ lua_pushnil(L); lua_pushstring(L, "no graph"); return 2; } return get_object(L, g); }
/*-------------------------------------------------------------------------*\ * Determines the graph to which of a node belongs. * Returns graph userdata. * Example: * rv = n.graph * Methods: n, err = e.head(self) and n, err = e.tail(self) \*-------------------------------------------------------------------------*/ static int gr_graphof(lua_State *L) { gr_edge_t *ud = toedge(L, 1, STRICT); gr_node_t *udh; Agnode_t *head, *tail; Agraph_t *g; int rv; head = ud->e->head; tail = ud->e->tail; rv = get_object(L, head); udh = tonode(L, -rv, STRICT); g = udh->subg; lua_pop(L, rv); return get_object(L, g); }
/*-------------------------------------------------------------------------*\ * Property: n.graph * Determines the graph to which of a node belongs. * Returns graph userdata. * Example: * rv = n.graph \*-------------------------------------------------------------------------*/ int gr_graphof(lua_State *L) { int rv; gr_node_t *ud = tonode(L, 1, STRICT); // Agraph_t *g = ud->n->u.subg; Agraph_t *g = ud->subg; if (g == NULL){ lua_pushnil(L); return 1; } rv = get_object(L, g); if (rv == 2){ lua_error(L); return 0; } else { return rv; } }
/*-------------------------------------------------------------------------* \ * Method: n.delete(self) * Delete a node. All associated edges are deleted as well. * Returns non-nil on success. * Example: * rv, err = n:delete(h) \*-------------------------------------------------------------------------*/ static int gr_delete(lua_State *L) { Agraph_t *g; gr_node_t *ud = tonode(L, 1, NONSTRICT); if (ud->n != NULL){ /* Delete all associated edges with tail on this node */ g = agraphof(ud->n); if (ud->status == ALIVE){ TRACE(" n.delete(): deleting node '%s' ud=%p id=0x%0lx (%s %d) \n", agnameof(ud->n), (void *) ud, (unsigned long) AGID(ud->n), __FILE__, __LINE__); agdelnode(g, ud->n); } } else { TRACE(" n:delete(): ud=%p already closed (%s %d)\n", (void *)ud, __FILE__, __LINE__); } lua_pushnumber(L, 0); return 1; }
/*-------------------------------------------------------------------------*\ * Write info about a node to stdout. * Example: * n:info() \*-------------------------------------------------------------------------*/ static int gr_info(lua_State *L) { Agraph_t *g; gr_node_t *ud = tonode(L, 1, STRICT); Agedge_t *se; Agsym_t *sym; g = agraphof(ud->n); printf("INFO NODE '%s' '%s' id=%lu seq=%d\n", agnameof(ud->n), ud->name, (unsigned long) AGID(ud->n), AGSEQ(ud->n)); printf(" ptr: %p\n", ud->n); printf(" Symbols:\n"); se = agfstout(g, ud->n); sym=0; while ((sym = agnxtattr(g,AGNODE,sym))!=NULL) printf(" %s = '%s'\n",sym->name,sym->defval); #if 0 printf(" Out edges: d-out=%d u-out=%d\n", agdegree(g, ud->n, 0, 1), agcountuniqedges(g, ud->n, 0, 1)); #endif while (se) { printf(" name: '%s', head: '%s', tail: '%s' id=%lud, seq=%d %p\n", agnameof(se), agnameof(aghead(se)), agnameof(agtail(se)), (unsigned long) AGID(se), AGSEQ(se), (void*)se); se = agnxtout(g, se); } #if 0 printf(" In edges: d-in=%d u-in=%d\n", agdegree(g, ud->n, 1, 0), agcountuniqedges(g, ud->n, 1, 0)); #endif se = agfstin(g, ud->n); while (se) { printf(" name: '%s', head: '%s', tail: '%s' îd=%lu seq=%d %p\n", agnameof(se), agnameof(aghead(se)), agnameof(agtail(se)), (unsigned long) AGID(se), AGSEQ(se), (void*)se); se = agnxtin(g, se); } #if 0 printf(" Edges: d-io=%d u-io=%d\n", agdegree(g, ud->n, 1, 1), agcountuniqedges(g, ud->n, 1, 1)); #endif se = agfstedge(g, ud->n); while (se) { printf(" name: '%s', head: '%s', tail: '%s' id=%lud seq=%d %p\n", agnameof(se), agnameof(aghead(se)), agnameof(agtail(se)), (unsigned long) AGID(se), AGSEQ(se), (void*)se); se = agnxtedge(g, se, ud->n); } return 0; }
/*-------------------------------------------------------------------------*\ * Method: n.rename(self, name) * Renames a graph. Null name will assign an auto-name 'node@ID'. * Returns old name. * Example: * oldname, err = n:rename("NODENEWNAME") or n:rename() \*-------------------------------------------------------------------------*/ static int gr_rename(lua_State *L) { char sbuf[32]; gr_node_t *ud = tonode(L, 1, STRICT); char *name = (char *) lua_tostring(L, 2); char *oldname = agnameof(ud->n); if (!name){ sprintf(sbuf, "node@%d", AGID(ud->n)); agrename(ud->n, agstrdup(sbuf)); free(ud->name); ud->name = strdup(sbuf); } else { agrename(ud->n, agstrdup(name)); free(ud->name); ud->name = strdup(name); } lua_pushstring(L, oldname); agstrfree(oldname); return 1; }
/*-------------------------------------------------------------------------*\ * Method: e = nextedge(self, prev) * Retrieves next edge of a node. * Returns the next edge of the given node. With nil as prev the first * edge is returned. * Example: * first = n:nextedge(nil) * second = n:nextedge(first) * third = n:nextedge(second) \*-------------------------------------------------------------------------*/ static int gr_nextedge(lua_State *L) { int rv; char sbuf[32]; Agraph_t *g; Agedge_t *e; gr_edge_t *ud_e; gr_node_t *ud_n = tonode(L, 1, STRICT); g = agroot(ud_n->n); if (lua_isnil(L, 2)){ e = agfstedge(g, ud_n->n); } else { ud_e = toedge(L, 2, STRICT); e = agnxtedge(g, ud_e->e, ud_n->n); } if (!e){ /* no more edges */ lua_pushnil(L); return 1; } else { /* Check whether userdata exists .. */ rv = get_object(L, e); if (rv == 1){ /* .. yes: return it */ return rv; } else { /* .. no: create it */ lua_pop(L, rv); ud_e = lua_newuserdata(L, sizeof(gr_edge_t)); ud_e->e = e; sprintf(sbuf, "edge@%lu", (unsigned long) AGID(e)); ud_e->name = strdup(sbuf); ud_e->type = AGEDGE; ud_e->status = ALIVE; set_object(L, e); return new_edge(L); } } }
/*-------------------------------------------------------------------------*\ * Method: n.delete(self) * Delete a node. All associated edges are deleted as well. * Returns non-nil on success. * Example: * rv, err = n:delete(h) \*-------------------------------------------------------------------------*/ static int gr_delete(lua_State *L) { Agraph_t *g; gr_node_t *ud = tonode(L, 1, NONSTRICT); if (ud->n != NULL){ /* Delete all associated edges with tail on this node */ Agedge_t *se, *ne; int ix; g = ud->n->graph; se = agfstedge(g, ud->n); while (se){ ne = agnxtedge(g, se, ud->n); ix = get_object(L, se); /* ud, se */ if (!(lua_isnil(L, -ix))){ TRACE("n:delete(): closing subedge: ud=%p 'edge@%d' id=0x%0x e=%p\n", (void *) lua_touserdata(L, -ix), AGID(se), AGID(se), (void *)se); lua_pushcfunction(L, gr_delete_edge); /* ud, se, func */ lua_pushvalue(L, -2); /* ud, se, func, se */ lua_call(L, 1, LUA_MULTRET); /* ud, se */ lua_pop(L, 1); /* ud */ } else { lua_pop(L, 2); /* ud */ } se = ne; } TRACE("n:delete(): ud=%p '%s' id=0x%0x \n", (void *) ud, agnameof(ud->n), AGID(ud->n)); del_object(L, ud->n); agdelete(g, ud->n); ud->n = NULL; if (ud->name){ free(ud->name); ud->name = NULL; } } else { TRACE("n:delete(): ud=%p already closed\n", (void *)ud); } lua_pushnumber(L, 0); return 1; }
static int gr_nextinout(lua_State *L, edge_first_iter_t *fst, edge_next_iter_t *nxt) { int rv; Agedge_t *e; char sbuf[32]; gr_edge_t *ud_e; gr_node_t *ud_n = tonode(L, 1, STRICT); Agraph_t *g = agroot(ud_n->n); if (lua_isnil(L, 2)) e = fst(g, ud_n->n); else { ud_e = toedge(L, 2, STRICT); e = nxt(g, ud_e->e); } if (!e){ /* no more nodes */ lua_pushnil(L); return 1; } else { /* Check whether userdata exists .. */ rv = get_object(L, e); if (rv == 1) /* .. yes: return it */ return rv; else { /* .. no: create it */ lua_pop(L, rv); ud_e = lua_newuserdata(L, sizeof(gr_edge_t)); ud_e->e = e; sprintf(sbuf, "edge@%lu", (unsigned long) AGID(e)); ud_e->name = strdup(sbuf); ud_e->type = AGEDGE; set_object(L, e); return new_edge(L); } } }
/*-------------------------------------------------------------------------*\ * Method: e, tail, head = n.edge(self, node, label, flag) * Finds or creates an edge. The given node is the tail of the edge. * The created node is the the edge. * Label is optional. * The optional flag nocreate=true inhibits auto-creation of the edge. * Any node given by name is implicitly created and it's userdata returned * as additional results - even if nocreate is not set. * Example: * e, tail, head = n.edge(head, "edge-1", true | false) * e, tail, head = e:node("headname", "edge-1", true | false) \*-------------------------------------------------------------------------*/ static int gr_edge(lua_State *L) { Agedge_t *e; gr_edge_t *edge; int rv; char *label; char ename[32]; Agraph_t *g; gr_node_t *head; gr_node_t *tail = tonode(L, 1, STRICT); g = agroot(tail->n); if (lua_isuserdata(L, 2)) head = tonode(L, 2, STRICT); else { lua_pushcfunction(L, gr_create_node); /* tail, nhead, (label), (nocreate), func */ get_object(L, agroot(tail->n)); /* tail, nhead, (label), (nocreate), func, graph */ lua_pushvalue(L, 2); /* ... func, graph, nhead */ if (lua_isboolean(L, 4)) lua_pushvalue(L, 4); /* ... func, graph, nhead, (nocreate) */ else lua_pushboolean(L, 0); /* ... func, graph, nhead, false */ lua_call(L, 3, 1); /* tail, nhead, (label), head */ if (lua_isnil(L, -1)) return 2; head = tonode(L, -1, STRICT); lua_pop(L,1); /* tail, nhead, (label) */ } g = agroot(tail->n); if (g != agroot(head->n)){ luaL_error(L, "head/tail not in same graph"); } label = (char *) luaL_optstring(L, 3, NULL); /* ud, peer, name, (flag) */ if ((e = agedge(g, tail->n, head->n, label, 0)) != NULL){ rv = get_object(L, e); /* ud, peer, name, (flag), edge */ if (lua_isnil(L, -rv)){ /* not yet registered */ lua_pop(L, rv); /* ud, peer, name, (flag) */ edge = lua_newuserdata(L, sizeof(gr_edge_t)); /* ud, peer, name, (flag), edge */ edge->e = e; if (label) agset(e, "label", label); edge->name = strdup(agnameof(e)); edge->type = AGEDGE; edge->status = ALIVE; new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); /* ud, peer, name, (flag), edge, tail, head */ return 3; } else { /* Edge already registered */ lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return rv + 2; /* ud, peer, name, (flag), edge, tail, head */ } } else { /* Edge does not exist */ if (lua_toboolean(L, 4)){ lua_pushnil(L); lua_pushstring(L, "edge not found"); return 2; } edge = lua_newuserdata(L, sizeof(gr_edge_t)); sprintf(ename, "edge@%u", newid()); if ((edge->e = agedge(g, tail->n, head->n, ename, 1)) == NULL){ luaL_error(L, "agedge failed"); return 0; } if (label) agset(edge->e, "label", label); edge->name = strdup(agnameof(edge->e)); edge->type = AGEDGE; edge->status = ALIVE; new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return 3; } }
/*-------------------------------------------------------------------------*\ * Property: id [number] * Get a node's id. * Example: * n = n.id \*-------------------------------------------------------------------------*/ static int gr_id(lua_State *L) { gr_node_t *ud = tonode(L, 1, STRICT); lua_pushnumber(L, AGID(ud->n)); return 1; }
/*-------------------------------------------------------------------------*\ * Method: e, tail, head = n.edge(self, node, label, flag) * Finds or creates an edge. The given node becomes the tail of the edge. * Label is optional. * The optional flag nocreate=true inhibits auto-creation. * Any node given by name is implicitly created and it's userdata returned * as additional results - even if nocreate is not set. * Example: * e, tail, head = e:node(n2, "edge-1") * e, err = g:edge(...) \*-------------------------------------------------------------------------*/ static int gr_edge(lua_State *L) { Agedge_t *e; gr_edge_t *edge; int rv; char *label; char sbuf[32]; Agraph_t *g; gr_node_t *head; gr_node_t *tail = tonode(L, 1, STRICT); if (lua_isuserdata(L, 2)) head = tonode(L, 2, STRICT); else { /* Create a node given by name */ lua_pushcfunction(L, gr_create_node); /* tail, nhead, (label), func */ get_object(L, tail->n->graph); /* tail, nhead, (label), func, graph */ lua_pushstring(L, (const char *) luaL_checkstring(L, 2)); /* ... func, graph, nhead */ if (lua_isboolean(L, 4)) lua_pushvalue(L, 4); else lua_pushboolean(L, 0); /* g.node(self, name, flag) */ lua_call(L, 3, 1); /* tail, nhead, (label), head */ head = tonode(L, -1, STRICT); lua_pop(L,1); /* tail, nhead, (label) */ } g = tail->n->graph; if (tail->n->graph != head->n->graph){ luaL_error(L, "head/tail not in same graph"); } label = (char *) luaL_optstring(L, 3, ""); /* ud, peer, name, (flag) */ if ((e = agfindedge(g, tail->n, head->n)) != NULL){ /* Edge exists */ rv = get_object(L, e); /* ud, peer, name, (flag), edge */ if (lua_isnil(L, -rv)){ lua_pop(L, rv); /* ud, peer, name, (flag) */ /* Edge not yet registered */ edge = lua_newuserdata(L, sizeof(gr_edge_t)); /* ud, peer, name, (flag), edge */ edge->e = e; if (strlen(label) > 0) agset(e, "label", label); sprintf(sbuf, "edge@%d", AGID(e)); edge->name = strdup(sbuf); edge->type = AGEDGE; set_object(L, e); /* ud, peer, name, (flag), edge */ new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); /* ud, peer, name, (flag), edge, tail, head */ return 3; } else { /* Edge already registered */ lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return rv + 2; /* ud, peer, name, (flag), edge, tail, head */ } } else { /* Edge does not exist */ if (lua_toboolean(L, 4)){ lua_pushnil(L); lua_pushstring(L, "edge not found"); return 2; } edge = lua_newuserdata(L, sizeof(gr_edge_t)); if (!(edge->e = agedge(g, tail->n, head->n))){ luaL_error(L, "agedge failed"); return 0; } if (strlen(label) > 0) agset(edge->e, "label", label); sprintf(sbuf, "edge@%d", AGID(edge->e)); edge->name = strdup(sbuf); edge->type = AGEDGE; set_object(L, edge->e); new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return 3; } }
/*-------------------------------------------------------------------------*\ * Property: name [string] * Provides the name of a node. * Example: * name = g.name \*-------------------------------------------------------------------------*/ static int gr_nameof(lua_State *L) { gr_node_t *ud = tonode(L, 1, STRICT); lua_pushstring(L, agnameof(ud->n)); return 1; }