fixed graph._SYSTEM for Linux
[luagraph.git] / src / gr_graph.c
blobe3c86afec787069d04da677f627d1e2214d04655
1 /*=======================rap==================================================*\
2 * LuaGRAPH toolkit
3 * Graph support for Lua.
4 * Herbert Leuwer
5 * 30-7-2006, 30-12-2016, 01/2017
7 * Graph related functionality.
9 \*=========================================================================*/
11 /*=========================================================================*\
12 * Includes
13 \*=========================================================================*/
14 #include <string.h>
15 #include <stdlib.h>
17 #include "lua.h"
18 #include "lauxlib.h"
20 #include "gr_graph.h"
21 #include "graphviz/cdt.h"
22 #include "graphviz/gvplugin.h"
24 /*=========================================================================*\
25 * Defines
26 \*=========================================================================*/
27 #define MYNAME "graph"
28 #define MYVERSION "2.2.0"
29 #if defined(_WIN32) || defined(WIN32)
30 #define MYGVVERSION "2.0.38"
31 #define MYSYSTEM "Win32"
32 #else
33 #if defined(__linux__)
34 #define MYSYSTEM "Linux"
35 #define MYGVVERSION GVVERSION
36 #else
37 #define MYSYSTEM "other"
38 #define MYGVVERSION GVVERSION
39 #endif
40 #endif
41 #define MYCOPYRIGHT "Copyright (C) 2006-2024, Herbert Leuwer "
42 #define MYDESCRIPTION "LuaGRAPH is a library for creating, manipulating and rendering GRAPHs (based on the GRAPHVIZ library cgraph)."
43 #ifndef NIL
44 #define NIL(x) ((x) NULL)
45 #endif
46 /*=========================================================================*\
47 * Prototypes
48 \*=========================================================================*/
49 static int gr_open(lua_State *L);
50 static int gr_close(lua_State *L);
51 static int gr_nameof(lua_State *L);
52 static int gr_write(lua_State *L);
53 static int gr_read(lua_State *L);
54 static int gr_memread(lua_State *L);
55 static int gr_isstrict(lua_State *L);
56 static int gr_isdirected(lua_State *L);
57 static int gr_nnodes(lua_State *L);
58 static int gr_nedges(lua_State *L);
59 static int gr_subgraph(lua_State *L);
60 static int gr_root(lua_State *L);
61 static int gr_parent(lua_State *L);
62 static int gr_equal(lua_State *L);
63 static int gr_getnext(lua_State *L);
64 static int gr_walk(lua_State *L);
65 static int gr_id(lua_State *L);
66 static int gr_isroot(lua_State *L);
67 static int gr_getgraphattr(lua_State *L);
68 static int gr_getnodeattr(lua_State *L);
69 static int gr_getedgeattr(lua_State *L);
70 static int gr_getattr(lua_State *L);
71 static int gr_setgraphattr(lua_State *L);
72 static int gr_setnodeattr(lua_State *L);
73 static int gr_setedgeattr(lua_State *L);
74 static int gr_setattr(lua_State *L);
75 static int gr_delete(lua_State *L);
76 static int gr_node(lua_State *L);
77 static int gr_edge(lua_State *L);
78 static int gr_findedge(lua_State *L);
79 static int gr_idnode(lua_State *L);
80 static int gr_nextnode(lua_State *L);
81 static int gr_walknodes(lua_State *L);
82 static int gr_graphof(lua_State *L);
83 static int gr_contains(lua_State *L);
84 static int gr_layout(lua_State *L);
85 static int gr_freelayout(lua_State *L);
86 static int gr_render(lua_State *L);
87 static int gr_plugins(lua_State *L);
88 static int gr_tostring(lua_State *L);
90 /*=========================================================================*\
91 * Data
92 \*=========================================================================*/
93 GVC_t *gvc = NULL;
95 #ifdef USE_BUILTIN_PLUGINS
96 extern gvplugin_library_t gvplugin_dot_layout_LTX_library;
97 extern gvplugin_library_t gvplugin_neato_layout_LTX_library;
98 extern gvplugin_library_t gvplugin_gd_LTX_library;
99 extern gvplugin_library_t gvplugin_pango_LTX_library;
100 #if 0
101 extern gvplugin_library_t gvplugin_webp_LTX_library;
102 #endif
103 extern gvplugin_library_t gvplugin_core_LTX_library;
105 lt_symlist_t lt_preloaded_symbols[] = {
106 { "gvplugin_dot_layout_LTX_library", (void*)(&gvplugin_dot_layout_LTX_library) },
107 { "gvplugin_neato_layout_LTX_library", (void*)(&gvplugin_neato_layout_LTX_library) },
108 { "gvplugin_pango_LTX_library", (void*)(&gvplugin_pango_LTX_library) },
109 #if 0
110 { "gvplugin_webp_LTX_library", (void*)(&gvplugin_webp_LTX_library) },
111 #endif
112 { "gvplugin_gd_LTX_library", (void*)(&gvplugin_gd_LTX_library) },
113 { "gvplugin_core_LTX_library", (void*)(&gvplugin_core_LTX_library) },
114 { 0, 0 }
116 #else
117 lt_symlist_t lt_preloaded_symbols[] = {
118 { 0, 0 }
120 #endif
122 * Base library functions
124 static const luaL_Reg funcs[] = {
125 {"open", gr_open},
126 {"close", gr_close},
127 {"read", gr_read},
128 {"memread", gr_memread},
129 {"equal", gr_equal},
130 {NULL, NULL}
134 * Graph object methods
136 static const luaL_Reg reg_methods[] = {
137 {"close", gr_close},
138 {"write", gr_write},
139 {"subgraph", gr_subgraph},
140 {"getnext", gr_getnext},
141 {"nextgraph", gr_getnext},
142 {"walk", gr_walk},
143 {"walkgraphs", gr_walk},
144 {"getgraphattr", gr_getgraphattr},
145 {"getnodeattr", gr_getnodeattr},
146 {"getedgeattr", gr_getedgeattr},
147 {"getattr", gr_getattr},
148 {"defaults", gr_getattr},
149 {"setgraphattr", gr_setgraphattr},
150 {"setnodeattr", gr_setnodeattr},
151 {"setedgeattr", gr_setedgeattr},
152 {"setattr", gr_setattr},
153 {"declare", gr_setattr},
154 {"delete", gr_delete},
155 {"node", gr_node},
156 {"edge", gr_edge},
157 {"findedge", gr_findedge},
158 {"idnode", gr_idnode},
159 {"nextnode", gr_nextnode},
160 {"walknodes", gr_walknodes},
161 {"type", get_object_type},
162 {"contains", gr_contains},
163 {"layout", gr_layout},
164 {"freelayout", gr_freelayout},
165 {"render", gr_render},
166 {"rawget", getval},
167 {NULL, NULL}
171 * Read-only members
173 static const luaL_Reg reg_rmembers[] = {
174 {"nnodes", gr_nnodes},
175 {"nedges", gr_nedges},
176 {"name", gr_nameof},
177 {"status", gr_status},
178 {"root", gr_root},
179 {"parent", gr_parent},
180 {"isstrict", gr_isstrict},
181 {"isdirected", gr_isdirected},
182 {"isroot", gr_isroot},
183 {"graph", gr_graphof},
184 {"id", gr_id},
185 {NULL, NULL}
189 * Standard metamethods
191 static const luaL_Reg reg_metamethods[] = {
192 {"__gc", gr_collect},
193 {"__eq", gr_equal},
194 {"__newindex", object_newindex_handler},
195 {"__tostring", gr_tostring},
196 {NULL, NULL}
200 * Event callback functions - used for registring/unregstring proxy objects
201 * in Lua registry.
203 static const struct Agcbdisc_s disc = {
204 { cb_insert, cb_modify, cb_delete}, /* graph callbacks */
205 { cb_insert, cb_modify, cb_delete}, /* node callbacks */
206 { cb_insert, cb_modify, cb_delete}, /* edge callbacks */
209 /*=========================================================================*\
210 * Functions
211 \*=========================================================================*/
212 /*-------------------------------------------------------------------------*\
213 * Utility Functions
214 \*-------------------------------------------------------------------------*/
217 * Create a new Lua userdata object and configure metatable.
219 static int new_graph(lua_State *L){
220 return new_object(L, "graph", reg_rmembers, reg_methods,
221 reg_metamethods, object_index_handler);
224 #define DEMAND_LOADING (1)
227 * Layout a graph using given engine.
229 static int gv_layout(Agraph_t *g, const char *engine)
231 int rv = gvLayout(gvc, g, engine);
232 if (rv != 0)
233 return GR_ERROR;
234 return GR_SUCCESS;
237 static int gv_free_layout(Agraph_t *g)
239 int rv = gvFreeLayout(gvc, g);
240 if (rv != 0)
241 return GR_ERROR;
242 return GR_SUCCESS;
246 * Render layouted graph into a file given by file handle
247 * using given format.
249 static int gv_render(Agraph_t *g, const char *fmt, FILE *fout)
251 int rv = gvRender(gvc, g, fmt, fout);
252 if (rv != 0)
253 return GR_ERROR;
254 return GR_SUCCESS;
257 * Render layouted graph into a file given by file name using given
258 * format.
260 static int gv_render_file(Agraph_t *g, const char *fmt, const char *fname)
262 int rv = gvRenderFilename(gvc, g, fmt, fname);
263 if (rv != 0)
264 return GR_ERROR;
265 return GR_SUCCESS;
269 * Gets attributes for a specific object type into a table rt.
270 * If no attributes are defined, the function returns an empty table.
271 * Lua entry stack: ud
272 * Lua exit stack: ud, rt
274 static int getattr(lua_State *L, int kind)
276 gr_graph_t *ud = tograph(L, 1, STRICT);
277 Agsym_t *sym = NULL;
279 lua_newtable(L); /* rt */
280 switch (kind){
281 case AGRAPH:
282 case AGNODE:
283 case AGEDGE:
284 while ((sym = agnxtattr(ud->g, kind, sym)) != NULL){
285 lua_pushstring(L, sym->name); /* rt, key */
286 lua_pushstring(L, sym->defval); /* rt, key, value */
287 lua_settable(L, -3); /* rt */
289 return 1;
290 break;
291 default:
292 return luaL_error(L, "invalid kind");
293 break;
298 * Sets attributes for a specific object type from a table.
299 * Lua entry stack: ud, t
300 * Lua exit stack: ud, t
302 static int setattr(lua_State *L, int kind)
304 int n = 0;
305 char *key;
306 char *value;
307 gr_graph_t *ud = tograph(L, 1, STRICT);
309 /* Parameter check */
310 luaL_checktype(L, -1, LUA_TTABLE);
312 /* traverse through all key/value pairs of given table */
313 lua_pushnil(L); /* t, nil */
314 while (lua_next(L, -2)){ /* t, key, val */
315 if (!lua_isstring(L, -2)){
316 lua_pop(L, 2); /* t */
317 luaL_error(L, "invalid key");
318 return 0;
320 key = (char *) lua_tostring(L, -2);
321 value = (char *) lua_tostring(L, -1);
322 if (value == NULL){
323 lua_pop(L,2);
324 luaL_error(L, "invalid value");
325 return 0;
327 lua_pop(L, 1); /* t, key */
328 n++;
329 agattr(ud->g, kind, key, value);
331 lua_pushnumber(L, n);
332 return 1;
335 /*-------------------------------------------------------------------------* \
336 * Function: g, err = graph.open(name [,kind])
337 * Create a new graph
338 * Returns graph userdata.
339 * Example:
340 * g, err = graph.open(name[, kind])
341 \*-------------------------------------------------------------------------*/
342 static int gr_open(lua_State *L)
344 gr_graph_t *ud;
345 Agdesc_t kind = Agdirected;
346 char *name = (char *) luaL_checkstring(L, 1);
347 char *skind = (char *) luaL_optstring(L, 2, "directed");
349 if (!strcmp(skind, "directed")) {
350 kind = Agdirected;
351 } else if (!strcmp(skind, "strictdirected")){
352 kind = Agstrictdirected;
353 } else if (!strcmp(skind, "undirected")) {
354 kind = Agundirected;
355 } else if (!strcmp(skind, "strictundirected")) {
356 kind = Agstrictundirected;
357 } else {
358 luaL_error(L, "invalid graph attribute");
361 /* Create a userdata */
362 ud = lua_newuserdata(L, sizeof(gr_graph_t)); /* ud */
363 if (!(ud->g = agopen(name, kind, &AgDefaultDisc))){
364 lua_pushnil(L);
365 lua_pushstring(L, "open failed");
366 return 2;
368 ud->name = strdup(name);
369 ud->type = AGRAPH;
370 ud->status = ALIVE;
371 /* We need a few default fields */
372 if (!agattr(ud->g, AGEDGE, "label", "") ||
373 !agattr(ud->g, AGRAPH, "__attrib__", "") ||
374 !agattr(ud->g, AGEDGE, "__attrib__", "") ||
375 !agattr(ud->g, AGNODE, "__attrib__", "")){
376 luaL_error(L, "declaration failed");
377 return 0;
380 /* We set callbacks only in root graph */
381 if (ud->g == agroot(ud->g)){
382 agpushdisc(ud->g, (struct Agcbdisc_s *)&disc, L);
385 set_object(L, ud->g);
386 return new_graph(L);
389 /*-------------------------------------------------------------------------*\
390 * Method: g.close(self)
391 * Close a graph
392 * Returns always 0.
393 * Example:
394 * rv = graph.close(g)
395 * rv = g:close()
396 \*-------------------------------------------------------------------------*/
397 static int gr_close(lua_State *L)
399 gr_graph_t *ud = tograph(L, 1, STRICT);
401 if (ud->g != NULL){
403 if (ud->status == ALIVE) {
404 /* Delete the graph, if it still exists */
405 TRACE(" g:close(): graph: ud=%p '%s' ptr=%p type=%d (%s %d)\n",
406 (void *) ud, agnameof(ud->g), (void *)ud->g, AGTYPE(ud->g), __FILE__, __LINE__);
407 agclose(ud->g);
409 } else {
410 TRACE(" g:close(): graph: ud=%p already closed (%s %d)\n", (void *) ud, __FILE__, __LINE__);
412 lua_pushnumber(L, 0);
413 return 1;
417 /*-------------------------------------------------------------------------*\
418 * Property: name [string]
419 * Returns the name of a graph.
420 * Example:
421 * name = g.name
422 \*-------------------------------------------------------------------------*/
423 static int gr_nameof(lua_State *L)
425 gr_graph_t *ud = tograph(L, 1, STRICT);
426 if (ud->status != ALIVE){
427 luaL_error(L, "deleted");
428 return 0;
430 lua_pushstring(L, agnameof(ud->g));
431 return 1;
434 /*-------------------------------------------------------------------------*\
435 * Property: isstrict [boolean]
436 * Returns true is graph is strict, otherwise it returns false.
437 * Example:
438 * rv = g.isstrict
439 \*-------------------------------------------------------------------------*/
440 static int gr_isstrict(lua_State *L)
442 gr_graph_t *ud = tograph(L, 1, STRICT);
443 lua_pushboolean(L, agisstrict(ud->g));
444 return 1;
447 /*-------------------------------------------------------------------------*\
448 * Property: isdirected [boolean]
449 * Returns true if the graph is directed, otherwise it returns false
450 * Example:
451 * rv = g.isdirected
452 \*-------------------------------------------------------------------------*/
453 static int gr_isdirected(lua_State *L)
455 gr_graph_t *ud = tograph(L, 1, STRICT);
456 lua_pushboolean(L, agisdirected(ud->g));
457 return 1;
460 /*-------------------------------------------------------------------------* \
461 * Read a graph from a string
462 * Returns graph userdata.
463 * Example:
464 * g, err = graph.memread(str)
465 \*-------------------------------------------------------------------------*/
466 static int gr_memread(lua_State *L)
468 gr_graph_t *ud;
469 char *str = (char *)lua_tostring(L, 1);
471 ud = lua_newuserdata(L, sizeof(gr_graph_t));
472 if (!(ud->g = agmemread(str))){
473 lua_pushnil(L);
474 lua_pushstring(L, "agread failed");
475 return 2;
477 ud->name = strdup(agnameof(ud->g));
478 ud->type = AGRAPH;
479 ud->status = ALIVE;
481 /* We set callbacks only in root graph */
482 if (ud->g == agroot(ud->g)){
483 agpushdisc(ud->g, (struct Agcbdisc_s *)&disc, L);
485 set_object(L, ud->g);
486 return new_graph(L);
489 /*-------------------------------------------------------------------------* \
490 * Read a graph from a file; "stdin" reads from STDIN.
491 * Returns graph userdata.
492 * Example:
493 * g, err = graph.read(filename)
494 \*-------------------------------------------------------------------------*/
495 static int gr_read(lua_State *L)
497 gr_graph_t *ud;
498 FILE *fin;
499 char *fname = (char *)luaL_optstring(L, 1, "stdin");
501 if (!strcmp(fname, "stdin")){
502 fin = stdin;
503 } else {
504 fin = fopen(fname, "r");
506 if (!fin){
507 lua_pushnil(L);
508 lua_pushstring(L, "fopen failed");
509 return 2;
511 /* Create a userdata */
512 ud = lua_newuserdata(L, sizeof(gr_graph_t));
513 if (!(ud->g = agread(fin, NIL(Agdisc_t*)))){
514 fclose(fin);
515 lua_pushnil(L);
516 lua_pushstring(L, "agread failed");
517 return 2;
519 fclose(fin);
520 ud->name = strdup(agnameof(ud->g));
521 ud->type = AGRAPH;
522 ud->status = ALIVE;
524 /* We set callbacks only in root graph */
525 if (ud->g == agroot(ud->g)){
526 agpushdisc(ud->g, (struct Agcbdisc_s *)&disc, L);
528 set_object(L, ud->g);
529 return new_graph(L);
532 /*-------------------------------------------------------------------------*\
533 * Method: g.write(self, filename)
534 * Write a graph into a file.
535 * Returns 1 on success, nil plus error message on failure.
536 * rv, err = g:write(filename)
537 \*-------------------------------------------------------------------------*/
538 static int gr_write(lua_State *L)
540 int rv;
541 FILE *fout;
542 int stdflag = 0;
543 gr_graph_t *ud = tograph(L, 1, STRICT);
544 char *fname = (char*) luaL_optstring(L, 2, "__std__");
546 if (!strcmp(fname, "__std__")){
547 stdflag = 1;
548 fout = stdout;
549 } else {
550 fout = fopen(fname, "w+");
552 if (!fout){
553 lua_pushnil(L);
554 lua_pushstring(L, "fopen failed");
555 return 2;
557 rv = agwrite(ud->g, fout);
558 if (rv){
559 if (!stdflag)
560 fclose(fout);
561 lua_pushnil(L);
562 lua_pushstring(L, "agwrite failed");
563 return 2;
565 if (!stdflag)
566 fclose(fout);
567 lua_pushnumber(L, rv);
568 return 1;
571 /*-------------------------------------------------------------------------*\
572 * Property:nnodes [number]
573 * Provides the numebr of edges of a graph
574 * Example:
575 * rv = g.nnodes
576 \*-------------------------------------------------------------------------*/
577 static int gr_nnodes(lua_State *L)
579 gr_graph_t *ud = tograph(L, 1, STRICT);
580 lua_pushnumber(L, agnnodes(ud->g));
581 return 1;
584 /*-------------------------------------------------------------------------*\
585 * Property: nedges [number]
586 * Provides the number of edges of a graph.
587 * Example:
588 * rv = g.nedges
589 \*-------------------------------------------------------------------------*/
590 static int gr_nedges(lua_State *L)
592 gr_graph_t *ud = tograph(L, 1, STRICT);
593 lua_pushnumber(L, agnedges(ud->g));
594 return 1;
597 /*-------------------------------------------------------------------------*\
598 * Metamethod: __eq [boolean]
599 * Compare two graphs
600 * Example:
601 * g == h or g != h with metamethods
602 \*-------------------------------------------------------------------------*/
603 static int gr_equal(lua_State *L)
605 gr_graph_t *ud1 = tograph(L, 1, STRICT);
606 gr_graph_t *ud2 = tograph(L, 2, STRICT);
607 lua_pushboolean(L, (ud1->g == ud2->g));
608 return 1;
611 /*-------------------------------------------------------------------------*\
612 * Method: g.subgraph(self, name, nocreate)
613 * Find or create a subgraph. The optional flag nocreate=true inhibits creation.
614 * Returns graph userdata.
615 * Example:
616 * sg, err = g:subgraph(name)
617 \*-------------------------------------------------------------------------*/
618 static int gr_subgraph(lua_State *L)
620 int rv;
621 Agraph_t *g;
622 gr_graph_t *sg;
623 gr_graph_t *ud = tograph(L, 1, STRICT);
624 char *name = (char *) luaL_checkstring(L, 2);
626 /* Check wheter the subgraph already exists */
627 if ((g = agsubg(ud->g, name, 0)) != NULL){
629 /* Yes - return corresponing userdata */
630 rv = get_object(L, g);
631 if (lua_isnil(L, -rv)){
632 sg = lua_newuserdata(L, sizeof(gr_graph_t));
633 sg->g = g;
634 sg->name = strdup(name);
635 sg->type = AGRAPH;
636 sg->status = ALIVE;
637 return new_graph(L);
638 } else
639 return rv;
640 } else {
641 /* No - Create a new one */
642 if (lua_toboolean(L, 3)){
643 lua_pushnil(L);
644 lua_pushstring(L, "graph not found");
645 return 2;
647 sg = lua_newuserdata(L, sizeof(gr_graph_t));
648 if (!(sg->g = agsubg(ud->g, name, 1))){
649 lua_pushnil(L);
650 lua_pushstring(L, "agsubg failed");
651 return 2;
653 if (name)
654 sg->name = strdup(name);
655 sg->type = AGRAPH;
656 sg->status = ALIVE;
657 return new_graph(L);
661 /*-------------------------------------------------------------------------*\
662 * Property: root [userdata]
663 * Get root of graph.
664 * Example:
665 * sg, err = g.root
666 \*-------------------------------------------------------------------------*/
667 static int gr_root(lua_State *L)
669 gr_graph_t *ud = tograph(L, 1, STRICT);
670 Agraph_t *g;
672 if (!(g = agroot(ud->g))){
673 lua_pushnil(L);
674 lua_pushstring(L, "agroot failed");
676 lua_pop(L, 1); /* empty */
677 return get_object(L, g); /* root */
680 /*-------------------------------------------------------------------------*\
681 * Property: parent [userdata]
682 * Get parent of graph.
683 * Example:
684 * sg, err = g.parent
685 \*-------------------------------------------------------------------------*/
686 static int gr_parent(lua_State *L)
688 gr_graph_t *ud = tograph(L, 1, STRICT);
689 Agraph_t *g = agparent(ud->g);
691 return get_object(L, g);
694 /*-------------------------------------------------------------------------*\
695 * Method: g = getnext(self, prev)
696 * Retrieves next subgraph in a graph hierarchy.
697 * Returns the successor of the given graph. With nil for parameter prev the
698 * first successor is returned.
699 * Example:
700 * first = g:getnext(nil)
701 * second = g:getnext(first)
702 * third = g:getnext(second)
703 \*-------------------------------------------------------------------------*/
704 static int gr_getnext(lua_State *L)
706 int rv;
707 Agraph_t *g;
708 gr_graph_t *ud_sg;
709 gr_graph_t *ud = tograph(L, 1, STRICT);
710 if (lua_isnil(L, 2)){
711 g = agfstsubg(ud->g);
712 } else {
713 ud_sg = tograph(L, 2, STRICT);
714 g = agnxtsubg(ud_sg->g);
716 if (!g){
717 lua_pushnil(L);
718 return 1;
719 } else {
720 rv = get_object(L, g);
721 if (rv == 1)
722 return rv;
723 else {
724 lua_pop(L, rv);
725 ud_sg = lua_newuserdata(L, sizeof(gr_graph_t));
726 ud_sg->g = g;
727 ud_sg->name = strdup(agnameof(g));
728 ud_sg->type = AGRAPH;
729 ud_sg->status = ALIVE;
730 set_object(L, g);
731 return new_graph(L);
736 /*-------------------------------------------------------------------------*\
737 * Iterator: g.walk(self)
738 * Iterator over all subgraphs of the given graph.
739 * Example:
740 * for g in g:walk() do ... end
741 \*-------------------------------------------------------------------------*/
742 static int gr_walk(lua_State *L)
744 lua_pushcfunction(L, gr_getnext); /* ud, getnext - iterator func */
745 lua_pushvalue(L, -2); /* ud, getnext, g - state */
746 lua_pushnil(L); /* ud, getnext, g, nil - initial param = nil*/
747 return 3;
750 /*-------------------------------------------------------------------------*\
751 * Property: id [number]
752 * Get a graph's id.
753 * Example:
754 * n = g.id
755 \*-------------------------------------------------------------------------*/
756 static int gr_id(lua_State *L)
758 gr_graph_t *ud = tograph(L, 1, STRICT);
759 lua_pushnumber(L, AGID(ud->g));
760 return 1;
763 /*-------------------------------------------------------------------------*\
764 * Property: isroot [boolean]
765 * Is given graph a root ?
766 * Example:
767 * b = g.isroot
768 \*-------------------------------------------------------------------------*/
769 static int gr_isroot(lua_State *L)
771 gr_graph_t *ud = tograph(L, 1, STRICT);
772 lua_pushboolean(L, agroot(ud->g) == ud->g);
773 return 1;
776 /*-------------------------------------------------------------------------*\
777 * Method: t, err = g.getgraphattr(self),
778 * t, err = g.getnodeattr(self),
779 * t, err = g.getedgeattr(self)
780 * Reads default attributes into a Lua table.
781 * Example:
782 * tab, err = g:getnodeattr()
783 \*-------------------------------------------------------------------------*/
784 static int gr_getgraphattr(lua_State *L)
786 return getattr(L, AGRAPH);
789 static int gr_getnodeattr(lua_State *L)
791 return getattr(L, AGNODE);
794 static int gr_getedgeattr(lua_State *L)
796 return getattr(L, AGEDGE);
799 /*-------------------------------------------------------------------------*\
800 * Method: t, err = g.getattr(self)
801 * Reads declarations/default attributes into a nested Lua table for format:
802 * t = {graph={name=val, ...}, node={name=val}, edge={name=val}}
803 * Example:
804 * tab, err = g:getattr()
805 \*-------------------------------------------------------------------------*/
806 static int gr_getattr(lua_State *L)
808 lua_newtable(L); /* ud, t */
810 lua_pushstring(L, "graph"); /* ud, t, key */
811 getattr(L, AGRAPH); /* ud, t, key, gt */
812 lua_settable(L, -3); /* ud, t */
814 lua_pushstring(L, "node"); /* ud, t, key */
815 getattr(L, AGNODE); /* ud, t, key, nt, n */
816 lua_settable(L, -3); /* ud, t */
818 lua_pushstring(L, "edge"); /* ud, t, key */
819 getattr(L, AGEDGE); /* ud, t, key, et, n */
820 lua_settable(L, -3); /* ud, t */
822 return 1;
825 /*-------------------------------------------------------------------------*\
826 * Method: n, err = g.setgraphattr(self, t),
827 * n, err = g.setnodeattr(self, t),
828 * n, err = g.setedgeattr(self, t)
829 * Sets default attributes from a Lua table t.
830 * Returns the number of attributes set.
831 * Example:
832 * rv, err = g:setnodeattr{shape="box", width=12}
833 \*-------------------------------------------------------------------------*/
834 static int gr_setgraphattr(lua_State *L)
836 return setattr(L, AGRAPH);
839 static int gr_setnodeattr(lua_State *L)
841 return setattr(L, AGNODE);
844 static int gr_setedgeattr(lua_State *L)
846 return setattr(L, AGEDGE);
849 /*-------------------------------------------------------------------------* \
850 * Method: n, err = g.setattr(self, t)
851 * Sets default attributes from a nested Lua table of format:
852 * see g.getattr(self) above.
853 * Returns the number of attributes set.
854 * Example:
855 * rv, err = g:setattr{graph={...}, node={shape="box"}, edge={...}}
856 \*-------------------------------------------------------------------------*/
857 static int gr_setattr(lua_State *L)
859 int n = 0;
860 int rv;
862 /* 1. Retrieve object specific attribute table from attribute table. */
863 lua_pushstring(L, "graph"); /* ud, t, key */
864 lua_gettable(L, -2); /* ud, t, gt */
865 if (!lua_isnil(L, -1)){
866 /* 2. Set/declare all object specific attribute */
867 rv = setattr(L, AGRAPH); /* ud, t, gt, n */
868 n += (int) lua_tonumber(L, -rv);
869 lua_pop(L, 2); /* ud, t */
870 } else
871 lua_pop(L, 1); /* ud, t */
873 /* 1. ... see above */
874 lua_pushstring(L, "node"); /* ud, t, key */
875 lua_gettable(L, -2); /* ud, t, nt */
876 if (!lua_isnil(L, -1)){
877 /* 2. ... see above */
878 rv = setattr(L, AGNODE); /* ud, t, nt, n */
879 n += (int) lua_tonumber(L, -rv);
880 lua_pop(L, 2); /* ud, t */
881 } else
882 lua_pop(L, 1); /* ud, t */
884 /* 1. ... see above */
885 lua_pushstring(L, "edge"); /* ud, t, key */
886 lua_gettable(L, -2); /* ud, t, et */
887 if (!lua_isnil(L, -1)){
888 /* 2. ... see above */
889 rv = setattr(L, AGEDGE); /* ud, t, et, n */
890 n += (int) lua_tonumber(L, -rv);
891 lua_pop(L, 2); /* ud, t */
892 } else
893 lua_pop(L, 1);
895 lua_pushnumber(L, n); /* ud, t, n */
896 return 1;
899 /*-------------------------------------------------------------------------*\
900 * Method: g.delete(self, obj)
901 * Deletes an object from the given graph.
902 * Returns non-nil.
903 * Example:
904 * rv, err = g:delete(n)
905 \*-------------------------------------------------------------------------*/
906 static int gr_delete(lua_State *L)
908 gr_object_t *obj = toobject(L, 2, NULL, STRICT);
909 TRACE(" g.delete(): obj: ud=%p ptr=%p type=%d (%s %d)\n",
910 (void *) obj, (void *) obj->p.p, AGTYPE(obj->p.p), __FILE__, __LINE__);
912 switch(AGTYPE(obj->p.p)){
913 case AGRAPH:
914 TRACE(" g.delete(): graph: ud=%p '%s' g=%p (%s %d)\n",
915 (void *)obj, agnameof(obj->g.g), (void *)obj->g.g, __FILE__, __LINE__);
916 lua_pushcfunction(L, gr_close); /* ud, obj, func */
917 lua_pushvalue(L, 2); /* ud, obj, func, obj */
918 lua_call(L, 1, 1); /* ud, obj, result */
919 lua_pop(L, 1); /* ud, obj */
920 break;
921 case AGNODE:
922 TRACE(" g:delete(): node: ud=%p '%s' g=%p (%s %d)\n",
923 (void *)obj, agnameof(obj->n.n), (void *)obj->n.n, __FILE__, __LINE__);
924 lua_pushcfunction(L, gr_delete_node);
925 lua_pushvalue(L, 2); /* ud, obj, func, obj */
926 lua_call(L, 1, 1); /* ud, obj, result */
927 lua_pop(L, 1); /* ud, obj */
928 break;
929 case AGEDGE:
930 TRACE(" g:delete(): edge: ud=%p '%s' g=%p (%s %d)\n",
931 (void *)obj, obj->p.name, (void *)obj->e.e, __FILE__, __LINE__);
932 lua_pushcfunction(L, gr_delete_edge);
933 lua_pushvalue(L, 2); /* ud, obj, func, obj */
934 lua_call(L, 1, 1); /* ud, obj, result */
935 lua_pop(L, 1); /* ud, obj */
936 break;
938 lua_pushnumber(L, 0);
939 return 1;
943 * A simple wrapper for usage of gr_node in other files.
945 int gr_create_node(lua_State *L)
947 return gr_node(L);
950 /*-------------------------------------------------------------------------* \
951 * Method: n, err = g.node(self [, name[, nocreate]])
952 * Finds or creates a node of given name. If name is nil autoname 'node@ID'
953 * is used. The optional flag nocreate=true inhibits auto-creation.
954 * Returns userdata.
955 * Examples:
956 * n, err = g:node("node-1", true)
957 * - Node will not be created, if it does not exists.
958 * n, err = g:node("node2")
959 * - Node will be created, if it does not exist.
960 * n, err = g:node()
961 * -
962 \*-------------------------------------------------------------------------*/
963 static int gr_node(lua_State *L)
965 Agnode_t *n;
966 gr_node_t *node;
967 int rv;
968 char *name;
970 /* param 1: graph = self */
971 gr_graph_t *ud = tograph(L, 1, STRICT);
973 name = (char *) luaL_checkstring(L, 2); /* ud, name */
975 if (name && (n = agnode(ud->g, name, 0)) != NULL){
976 rv = get_object(L, n); /* ud, name, node/nil */
977 if (lua_isnil(L, -rv)){
978 lua_pop(L, rv); /* ud, name */
979 /* Node not yet registered */
980 node = lua_newuserdata(L, sizeof(gr_node_t)); /* ud, name, node */
981 node->n = n;
982 node->name = strdup(agnameof(n));
983 node->type = AGNODE;
984 node->status = ALIVE;
985 return new_node(L);
986 } else
987 /* Node already registered */
988 return rv; /* ud, name, node */
989 } else {
990 /* Node does not exist */
991 if (lua_toboolean(L, 3)){
992 /* auto-creation forbidden: return an error */
993 lua_pushnil(L);
994 lua_pushstring(L, "node not found");
995 return 2;
997 /* Enforce creation with given name or an intermediate name '__tempname__' */
998 node = lua_newuserdata(L, sizeof(gr_node_t));
999 if ( (name && (node->n = agnode(ud->g, name, 1)) == NULL)){
1000 luaL_error(L, "agnode failed");
1001 return 0;
1003 node->name = strdup(name);
1004 node->type = AGNODE;
1005 node->status = ALIVE;
1006 return new_node(L);
1010 /*-------------------------------------------------------------------------* \
1011 * Method: e, tail, head = g.edge(self, tail, head, label, nocreate)
1012 * Finds or creates an edge from tail to head with label. Parameter label
1013 * is optional.
1014 * The optional flag nocreate inhibits auto-creation of the edge.
1015 * Any node given by name is implicitly created and it's userdata returned
1016 * as additional results - even if nocreate is not set.
1017 * Userdata proxy object is registered on the fly, if not yet available.
1018 * Examples:
1019 * e, tail, head = g:edge(n1, "node@2", "n1 => n2"[, false|true])
1020 * e, tail, head = g:edge(n1, n2)
1021 * e, tail, head = g:edge("node@1", n2, nil, true)
1022 \*-------------------------------------------------------------------------*/
1023 static int gr_edge(lua_State *L)
1025 Agedge_t *e;
1026 gr_edge_t *edge;
1027 gr_node_t *tail, *head;
1028 int rv;
1029 char ename[32];
1030 char *label;
1031 int head_created = 0;
1032 int tail_created = 0;
1034 /* param 1: graph = self */
1035 gr_graph_t *ud = tograph(L, 1, STRICT);
1037 /* param 2: tail node */
1038 if (lua_isuserdata(L, 2) == 1) {
1039 tail = tonode(L, 2, STRICT);
1040 } else {
1041 /* Create a node given only by name */
1042 lua_pushcfunction(L, gr_node); /* ud, ntail, (n)head, [label], func */
1043 lua_pushvalue(L, 1); /* ud, ntail, (n)head, [label], func, ud */
1044 lua_pushstring(L, (const char *) luaL_checkstring(L, 2));
1045 /* g.node(self, name, flag) */
1046 lua_call(L, 2, 1); /* ud, ntail, (n)head, (label), tail */
1047 if (lua_isnil(L, -1)){
1048 return luaL_error(L, "tailnode create failed");
1051 tail = tonode(L, -1, STRICT);
1052 lua_pop(L, 1); /* ud, ntail, (n)head, (label) */
1053 tail_created = 1;
1055 /* param 3: head node */
1056 if (lua_isuserdata(L, 3))
1057 head = tonode(L, 3, STRICT);
1058 else {
1059 /* Create a node given only by name */
1060 lua_pushcfunction(L, gr_node); /* ud, ntail, (n)head, [label], func */
1061 lua_pushvalue(L, 1); /* ud, ntail, (n)head, [label], func, ud */
1062 lua_pushstring(L, (const char *) luaL_checkstring(L, 3));
1063 /* g.node(self, name, flag) */
1064 lua_call(L, 2, 1); /* ud, ntail, (n)head, (label), head */
1065 if (lua_isnil(L, -1)){
1066 del_object(L, tail);
1067 return luaL_error(L, "headnode create failed");
1069 head = tonode(L, -1, STRICT);
1070 lua_pop(L, 1); /* ud, ntail, (n)head, (label) */
1071 head_created = 1;
1074 /* param 4: label */
1075 label = (char *) luaL_optstring(L, 4, NULL); /* ud, tail, head */
1077 /* Check whether edge already exists - only required for strict graphs */
1078 if ((e = agedge(ud->g, tail->n, head->n, NULL, 0)) != NULL){
1079 TRACE(" gr_edge(): edge '%s' exists force=%d (%s %d)\n", agnameof(e), (int) lua_toboolean(L, 5), __FILE__, __LINE__);
1080 /* Edge exists */
1081 if (agisstrict(ud->g)) {
1082 /* strict directed graph: give edge a new label */
1083 agsafeset(e, "label", label, NULL);
1085 rv = get_object(L, e);
1086 if (lua_isnil(L, -rv)){
1087 rv = get_object(L, agopp(e));
1088 if (lua_isnil(L, -rv))
1089 return rv;
1091 lua_pushlightuserdata(L, tail);
1092 lua_pushlightuserdata(L, head);
1093 return 3;
1095 /* Edge doees not exist */
1096 if (lua_isboolean(L, 5)){
1097 /* creation of edge forbidden: nocreate flag is set */
1098 if (tail_created)
1099 del_object(L, tail->n);
1100 if (head_created)
1101 del_object(L, head->n);
1102 lua_pushnil(L);
1103 lua_pushstring(L, "edge not found");
1104 return 2;
1106 /* Enforce creation */
1107 edge = lua_newuserdata(L, sizeof(gr_edge_t));
1108 if (agroot(tail->n) != agroot(head->n)){
1109 luaL_error(L, "nodes in different graphs");
1110 return 0;
1112 sprintf(ename, "edge@%u", newid());
1113 if (!(edge->e = agedge(ud->g, tail->n, head->n, ename, 1))){
1114 /* creation failed */
1115 if (tail_created)
1116 del_object(L, tail->n);
1117 if (head_created)
1118 del_object(L, head->n);
1119 lua_pushnil(L);
1120 lua_pushstring(L, "agedge failed");
1121 return 2;
1123 TRACE(" gr_edge(): ud=%p '%s' l=%p g=%p e=%p tail=%p head=%p force=%d (%s %d)\n",
1124 (void *) edge, label, (void*) label, (void *)ud->g, (void *)edge->e,
1125 (void *)tail->n, (void *)head->n, (int) lua_toboolean(L, 5), __FILE__, __LINE__);
1126 if (label)
1127 agsafeset(edge->e, "label", label, NULL);
1128 edge->name = strdup(ename);
1129 edge->type = AGEDGE;
1130 edge->status = ALIVE;
1131 new_edge(L);
1132 lua_pushlightuserdata(L, tail);
1133 lua_pushlightuserdata(L, head);
1134 return 3;
1137 /*-------------------------------------------------------------------------*\
1138 * Method: n, err = g.findedge(self, tail, head [, name])
1139 * Finds an edge of given name between given nodes.
1140 * If multiple edges exist in non-directed graph, onle one of them is
1141 * retrieved, if name is not specified.
1142 * Returns proxy userdata.
1143 * Example:
1144 * e, tail, head = g:findedge(n1, "node@2", "edge@122")
1145 \*-------------------------------------------------------------------------*/
1146 static int gr_findedge(lua_State *L)
1148 Agedge_t *e;
1149 gr_edge_t *edge;
1150 int rv;
1151 char sbuf[32];
1152 gr_graph_t *ud = tograph(L, 1, STRICT);
1153 gr_node_t *tail = tonode(L, 2, STRICT);
1154 gr_node_t *head = tonode(L, 3, STRICT);
1155 char *name = (char *) luaL_optstring(L, 4, NULL); /* ud, tail, head, label */
1156 if ((e = agedge(ud->g, tail->n, head->n, name, 0)) != NULL){
1157 rv = get_object(L, e); /* ud, tail, head, (label), e/nil */
1158 if (lua_isnil(L, -rv)){
1159 rv = get_object(L, agopp(e)); /* ud, tail, head, (label), e/nil, nil/e */
1160 if (lua_isnil(L, -rv)){
1161 lua_pop(L, rv); /* ud, tail, head, (label) */
1162 /* Edge not yet registered */
1163 edge = lua_newuserdata(L, sizeof(gr_edge_t)); /* ud, peer, name, edge */
1164 edge->e = e;
1165 sprintf(sbuf, "edge@%lu", (unsigned long) AGID(e));
1166 edge->name = strdup(sbuf);
1167 edge->type = AGEDGE;
1168 edge->status = ALIVE;
1169 set_object(L, e); /* ud, peer, name, edge */
1170 new_edge(L);
1171 lua_pushlightuserdata(L, tail);
1172 lua_pushlightuserdata(L, head);
1173 return 3;
1174 } else {
1175 /* Edge already registered */
1176 lua_pushlightuserdata(L, tail);
1177 lua_pushlightuserdata(L, head);
1178 return rv + 2; /* ud, peer, name, edge */
1180 } else {
1181 /* Edge already registered */
1182 lua_pushlightuserdata(L, tail);
1183 lua_pushlightuserdata(L, head);
1184 return rv + 2; /* ud, peer, name, edge */
1186 } else {
1187 lua_pushnil(L);
1188 lua_pushstring(L, "edge not found");
1189 return 2;
1192 /*-------------------------------------------------------------------------*\
1193 * Method: n, err = g.idnode(self, id)
1194 * Finds a node by id.
1195 * Returns userdata.
1196 * Example:
1197 * n, err = g:idnode(18)
1198 \*-------------------------------------------------------------------------*/
1199 static int gr_idnode(lua_State *L)
1201 Agnode_t *n;
1202 gr_graph_t *ud = tograph(L, 1, STRICT);
1203 unsigned long id = (unsigned long) luaL_checknumber(L, 2);
1204 if ((n = agidnode(ud->g, id, 0)) != NULL){
1205 return get_object(L, n);
1206 } else {
1207 lua_pushnil(L);
1208 lua_pushstring(L, "agidnode failed");
1209 return 2;
1213 /*-------------------------------------------------------------------------*\
1214 * Method: n = nextnode(self, prev)
1215 * Retrieves next node in a graph.
1216 * Returns the successor of the given node. With nil as parameter prev the
1217 * first node is returned.
1218 * Example:
1219 * first = g:nextnode(nil)
1220 * second = g:nextnode(first)
1221 * third = g:nextnode(second)
1222 \*-------------------------------------------------------------------------*/
1223 static int gr_nextnode(lua_State *L)
1225 int rv;
1226 Agnode_t *n;
1227 gr_node_t *ud_n;
1228 gr_graph_t *ud_g = tograph(L, 1, STRICT);
1229 if (lua_isnil(L, 2))
1230 n = agfstnode(ud_g->g);
1231 else {
1232 ud_n = tonode(L, 2, STRICT);
1233 n = agnxtnode(ud_g->g, ud_n->n);
1235 if (!n){
1236 /* no more nodes */
1237 lua_pushnil(L);
1238 return 1;
1239 } else {
1240 /* Check whether userdata exists .. */
1241 rv = get_object(L, n);
1242 if (rv == 1)
1243 /* .. yes: return it */
1244 return rv;
1245 else {
1246 /* .. no: create it */
1247 lua_pop(L, rv);
1248 ud_n = lua_newuserdata(L, sizeof(gr_node_t));
1249 ud_n->n = n;
1250 ud_n->name = strdup(agnameof(n));
1251 ud_n->type = AGNODE;
1252 ud_n->status = ALIVE;
1253 set_object(L, n);
1254 return new_node(L);
1259 /*-------------------------------------------------------------------------*\
1260 * Iterator: walknodes()
1261 * Iterator over all nodes of a given graph.
1262 * Example:
1263 * for n in g:walknodes() do ... end
1264 \*-------------------------------------------------------------------------*/
1265 static int gr_walknodes(lua_State *L)
1267 lua_pushcfunction(L, gr_nextnode); /* ud, nextnode */
1268 lua_pushvalue(L, -2); /* ud, nextnode, g */
1269 lua_pushnil(L); /* ud, nextnode, g, nil */
1270 return 3;
1273 /*-------------------------------------------------------------------------*\
1274 * Property: g.graph [userdata]
1275 * Retrieves the graph to which given subgraph belongs. Trivial because it
1276 * returns itself.
1277 * Returns graph userdata.
1278 * Example:
1279 * g, err = g.graph
1280 \*-------------------------------------------------------------------------*/
1281 int gr_graphof(lua_State *L)
1283 gr_graph_t *ud = tograph(L, 1, STRICT);
1284 Agraph_t *g = agraphof(ud->g);
1285 if (g == NULL){
1286 lua_pushnil(L);
1287 lua_pushstring(L, "no graph");
1288 return 2;
1290 return get_object(L, ud->g);
1293 /*-------------------------------------------------------------------------*\
1294 * Method: rv = g.contains(self, obj)
1295 * Returns true if graph g contains object obj.
1296 * Example:
1297 * b = g:contains(n)
1298 \*-------------------------------------------------------------------------*/
1299 int gr_contains(lua_State *L)
1301 gr_graph_t *ud = tograph(L, 1, STRICT);
1302 gr_object_t *obj = toobject(L, 2, NULL, STRICT);
1303 int rv = agcontains(ud->g, obj->p.p);
1304 if (rv && AGTYPE(obj->p.p) == AGNODE){
1305 if (agroot(obj->n.n) == agroot(ud->g))
1306 lua_pushboolean(L, TRUE);
1307 else
1308 lua_pushboolean(L, FALSE);
1309 } else
1310 lua_pushboolean(L, rv);
1311 return 1;
1314 /*-------------------------------------------------------------------------*\
1315 * Method: rv = g.layout(self, fmt)
1316 * Layout the given graph in the specified format/algorithm.
1317 * Example:
1318 * b = g:layout("dot")
1319 \*-------------------------------------------------------------------------*/
1320 static int gr_layout(lua_State *L)
1322 int rv;
1323 gr_graph_t *ud = tograph(L, 1, STRICT);
1324 char *fmt = (char *) luaL_optstring(L, 2, "dot");
1326 if (!strcmp(fmt, "dot") ||
1327 !strcmp(fmt, "neato") ||
1328 !strcmp(fmt, "nop") ||
1329 !strcmp(fmt, "nop2") ||
1330 !strcmp(fmt, "twopi") ||
1331 !strcmp(fmt, "fdp") ||
1332 !strcmp(fmt, "circo")){
1334 if ((rv = gv_layout(ud->g, fmt)) != GR_SUCCESS){
1335 luaL_error(L, "layout error: %d", rv);
1336 return 0;
1338 lua_pushvalue(L, rv);
1339 return 1;
1340 } else {
1341 luaL_error(L, "invalid layout format '%s'", fmt);
1342 return 0;
1346 /*-------------------------------------------------------------------------*\
1347 * Method: rv = g.freelayout(self, fmt)
1348 * Free a layout
1349 * Example:
1350 * b = g:freelayout()
1351 \*-------------------------------------------------------------------------*/
1352 static int gr_freelayout(lua_State *L)
1354 gr_graph_t *ud = tograph(L, 1, STRICT);
1355 if (ud->g)
1356 gv_free_layout(ud->g);
1357 else {
1358 lua_pushnil(L);
1359 lua_pushstring(L, "invalid graph");
1360 return 2;
1362 lua_pushnumber(L, 0);
1363 return 1;
1365 /*-------------------------------------------------------------------------*\
1366 * Method: rv = g.render(self, rfmt, file, lfmt)
1367 * Render the given graph in the specified format.
1368 * Example:
1369 * b = g:render("pdf")
1370 \*-------------------------------------------------------------------------*/
1371 static int gr_render(lua_State *L)
1373 int rv;
1374 gr_graph_t *ud = tograph(L, 1, STRICT);
1375 char *rfmt = (char *) luaL_optstring(L, 2, "plain");
1376 char *fname = (char *) luaL_optstring(L, 3, NULL);
1377 char *lfmt = (char *) luaL_optstring(L, 4, NULL);
1378 if (gvc == NULL){
1379 lua_pushnil(L);
1380 lua_pushstring(L, "layout missing");
1381 return 2;
1383 if (lfmt)
1384 gv_layout(ud->g, lfmt);
1385 if (fname)
1386 rv = gv_render_file(ud->g, rfmt, fname);
1387 else
1388 rv = gv_render(ud->g, rfmt, stdout);
1389 if (lfmt)
1390 gv_free_layout(ud->g);
1391 if (rv != GR_SUCCESS){
1392 lua_pushnil(L);
1393 lua_pushstring(L, "gvRender failed");
1394 return 2;
1396 lua_pushnumber(L, rv);
1397 return 1;
1400 /*-------------------------------------------------------------------------*\
1401 * Method: list, count = graph.plugins(type)
1402 * Retrieve available plugins for layout or rendering.
1403 * type: layout | render
1404 * Example:
1405 * tab, err = g:layout("layout")
1406 \*-------------------------------------------------------------------------*/
1407 static int gr_plugins(lua_State *L)
1409 int i, count;
1410 char **list;
1412 char *kind = (char *) luaL_optstring(L, 1, "render");
1413 #if 1
1414 list = gvPluginList(gvc, kind, &count, NULL);
1415 #else
1416 list = gvPluginList(gvc, kind, &count);
1417 #endif
1418 if (list == NULL){
1419 lua_pushnil(L);
1420 lua_pushstring(L, "no plugins");
1421 return 2;
1424 lua_newtable(L); /* t */
1425 for (i = 0; i < count; i++){
1426 lua_pushnumber(L, i+1); /* t, index */
1427 lua_pushstring(L, list[i]); /* t, index, value */
1428 lua_settable(L, -3); /* t */
1430 lua_pushnumber(L, count);
1431 for (i = 0; i < count; i++)
1432 free(list[i]);
1433 free(list);
1434 return 2;
1436 /*-------------------------------------------------------------------------*\
1437 * Module initialization
1438 \*-------------------------------------------------------------------------*/
1439 LUALIB_API int luaopen_graph_core(lua_State *L) {
1440 lua_newtable(L);
1441 lua_pushvalue(L, -1);
1442 lua_setglobal(L, MYNAME);
1443 register_metainfo(L, funcs);
1444 lua_pushliteral(L, "version");
1445 lua_pushliteral(L, MYVERSION);
1446 lua_rawset(L, -3);
1447 lua_pushliteral(L, "_VERSION");
1448 lua_pushliteral(L, MYVERSION);
1449 lua_rawset(L, -3);
1450 lua_pushliteral(L, "_GVVERSION");
1451 lua_pushliteral(L, MYGVVERSION);
1452 lua_rawset(L, -3);
1453 lua_pushliteral(L, "_COPYRIGHT");
1454 lua_pushliteral(L, MYCOPYRIGHT);
1455 lua_rawset(L, -3);
1456 lua_pushliteral(L, "_DESCRIPTION");
1457 lua_pushliteral(L, MYDESCRIPTION);
1458 lua_rawset(L, -3);
1459 lua_pushliteral(L, "_SYSTEM");
1460 lua_pushliteral(L, MYSYSTEM);
1461 lua_rawset(L, -3);
1462 lua_pushliteral(L, "plugins");
1463 lua_pushcfunction(L, gr_plugins);
1464 lua_rawset(L, -3);
1465 if ((gvc = gvContextPlugins(lt_preloaded_symbols, DEMAND_LOADING)) == NULL){
1466 return luaL_error(L, "cannot load plugins");
1468 return 1;
1471 /*-------------------------------------------------------------------------*\
1472 * Metamethod: __tostring [boolean]
1473 * Return a string presentation of a graph object.
1474 * Example:
1475 * g == h or g != h with metamethods
1476 \*-------------------------------------------------------------------------*/
1477 static int gr_tostring(lua_State *L)
1479 gr_object_t *ud = toobject(L, 1, NULL, NONSTRICT);
1480 lua_pushfstring(L, "graph: %p (%s)", ud, ud->p.status == ALIVE ? "alive" : "dead");
1481 return 1;