#include #include #include #include "graphviz_swiprolog.h" static GVC_t *gvc; #define PL_check(result) \ if (!(result)) { \ PL_fail; \ } int PL_get_desc(term_t desc_term, Agdesc_t *desc) { char *desc_string; PL_check(PL_get_atom_chars(desc_term, &desc_string)); if (strcmp(desc_string, "undirected") == 0) { *desc = Agundirected; } else if (strcmp(desc_string, "strict_undirected") == 0) { *desc = Agstrictundirected; } else if (strcmp(desc_string, "directed") == 0) { *desc = Agdirected; } else if (strcmp(desc_string, "strict_directed") == 0) { *desc = Agstrictdirected; } else { PL_fail; } PL_succeed; } int PL_get_graph(term_t graph_term, Agraph_t **graph) { return PL_get_pointer(graph_term, (void **) graph); } int PL_get_kind(term_t desc_term, int *kind) { char *desc_string; PL_check(PL_get_atom_chars(desc_term, &desc_string)); if (strcmp(desc_string, "graph") == 0) { *kind = AGRAPH; } else if (strcmp(desc_string, "node") == 0) { *kind = AGNODE; } else if (strcmp(desc_string, "out_edge") == 0) { *kind = AGOUTEDGE; } else if (strcmp(desc_string, "in_edge") == 0) { *kind = AGINEDGE; } else if (strcmp(desc_string, "edge") == 0) { *kind = AGEDGE; } else { PL_fail; } PL_succeed; } int PL_get_node(term_t graph_term, Agnode_t **node) { return PL_get_pointer(graph_term, (void **) node); } int PL_unify_graph_or_close(term_t graph_term, Agraph_t *graph) { int result = PL_unify_pointer(graph_term, graph); if (!result) { agclose(graph); } return result; } static foreign_t pl_agattr( term_t graph_term, term_t kind_term, term_t name_term, term_t value_term, term_t sym_term ) { Agraph_t *graph; int kind; char *name; char *value; Agsym_t *sym; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_kind(kind_term, &kind)); PL_check(PL_get_atom_chars(name_term, &name)); PL_check(PL_get_atom_chars(value_term, &value)); PL_check(sym = agattr(graph, kind, name, value)); PL_check(PL_unify_pointer(sym_term, sym)); PL_succeed; } static foreign_t pl_agclose(term_t graph_term) { Agraph_t *graph; PL_check(PL_get_graph(graph_term, &graph)); PL_check(!agclose(graph)); PL_succeed; } static foreign_t pl_agedge( term_t graph_term, term_t node0_term, term_t node1_term, term_t name_term, term_t create_flag_term, term_t edge_term ) { Agraph_t *graph; Agnode_t *node0; Agnode_t *node1; char *name; int create_flag; Agedge_t *edge; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_node(node0_term, &node0)); PL_check(PL_get_node(node1_term, &node1)); PL_check(PL_get_atom_chars(name_term, &name)); PL_check(PL_get_bool(create_flag_term, &create_flag)); PL_check(edge = agedge(graph, node0, node1, name, create_flag)); PL_check(PL_unify_pointer(edge_term, edge)); PL_succeed; } static foreign_t pl_agget(term_t object_term, term_t name_term, term_t value_term) { void *object; char *name; char *value; PL_check(PL_get_pointer(object_term, &object)); PL_check(PL_get_atom_chars(name_term, &name)); PL_check(value = agget(object, name)); PL_check(PL_unify_atom_chars(value_term, value)); PL_succeed; } static foreign_t pl_agnode( term_t graph_term, term_t name_term, term_t create_flag_term, term_t node_term ) { Agraph_t *graph; char *name; int create_flag; Agnode_t *node; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_atom_chars(name_term, &name)); PL_check(PL_get_bool(create_flag_term, &create_flag)); PL_check(node = agnode(graph, name, create_flag)); PL_check(PL_unify_pointer(node_term, node)); PL_succeed; } static foreign_t pl_agread(term_t filename_term, term_t graph_term) { char *filename; FILE *file; Agraph_t *graph; PL_check(PL_get_atom_chars(filename_term, &filename)); PL_check(file = fopen(filename, "r")); PL_check(graph = agread(file, 0)); PL_check(!fclose(file)); PL_check(PL_unify_graph_or_close(graph_term, graph)); PL_succeed; } static foreign_t pl_agopen(term_t name_term, term_t desc_term, term_t graph_term) { char *name; char *graph_type; Agdesc_t desc; Agraph_t *graph; PL_check(PL_get_atom_chars(name_term, &name)); PL_check(PL_get_desc(desc_term, &desc)); PL_check(graph = agopen(name, desc, 0)); PL_check(PL_unify_graph_or_close(graph_term, graph)); PL_succeed; } static foreign_t pl_agset(term_t object_term, term_t name_term, term_t value_term) { void *object; char *name; char *value; PL_check(PL_get_pointer(object_term, &object)); PL_check(PL_get_atom_chars(name_term, &name)); PL_check(PL_get_atom_chars(value_term, &value)); PL_check(!agset(object, name, value)); PL_succeed; } static foreign_t pl_agwrite(term_t graph_term, term_t filename_term) { Agraph_t *graph; char *filename; FILE *file; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_atom_chars(filename_term, &filename)); PL_check(file = fopen(filename, "w")); PL_check(!agwrite(graph, file)); PL_check(!fclose(file)); PL_succeed; } static foreign_t pl_gvFreeLayout(term_t graph_term) { Agraph_t *graph; PL_check(PL_get_graph(graph_term, &graph)); PL_check(!gvFreeLayout(gvc, graph)); PL_succeed; } static foreign_t pl_gvLayout(term_t graph_term, term_t engine_term) { Agraph_t *graph; char *engine; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_atom_chars(engine_term, &engine)); PL_check(!gvLayout(gvc, graph, engine)); PL_succeed; } static foreign_t pl_gvRenderFilename( term_t graph_term, term_t format_term, term_t filename_term ) { Agraph_t *graph; char *format; char *filename; FILE *file; PL_check(PL_get_graph(graph_term, &graph)); PL_check(PL_get_atom_chars(format_term, &format)); PL_check(PL_get_atom_chars(filename_term, &filename)); PL_check(!gvRenderFilename(gvc, graph, format, filename)); PL_succeed; } PL_extension graphviz_predicates[] = { { "agattr", 5, pl_agattr, 0 }, { "agclose", 1, pl_agclose, 0 }, { "agedge", 6, pl_agedge, 0 }, { "agget", 3, pl_agget, 0 }, { "agnode", 4, pl_agnode, 0 }, { "agopen", 3, pl_agopen, 0 }, { "agread", 2, pl_agread, 0 }, { "agset", 3, pl_agset, 0 }, { "agwrite", 2, pl_agwrite, 0 }, { "gvFreeLayout", 1, pl_gvFreeLayout, 0 }, { "gvLayout", 2, pl_gvLayout, 0 }, { "gvRenderFilename", 3, pl_gvRenderFilename, 0 }, { NULL, 0, NULL, 0 } }; install_t install_graphviz_swiprolog(void) { gvc = gvContext(); PL_register_extensions(graphviz_predicates); }