graphviz_swiprolog.c 6.79 KB
Newer Older
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
1
#include <stdio.h>
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
2
#include <SWI-Prolog.h>
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
3
#include <gvc.h>
4
#include "graphviz_swiprolog.h"
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
5

6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
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;
}
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
97 98 99 100

static foreign_t
pl_agclose(term_t graph_term) {
    Agraph_t *graph;
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
    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));
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
137 138 139
    PL_succeed;
}

140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
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;

}

MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
158 159 160 161 162
static foreign_t
pl_agread(term_t filename_term, term_t graph_term) {
    char *filename;
    FILE *file;
    Agraph_t *graph;
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
    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));
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
206 207
    PL_succeed;
}
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
208 209

static foreign_t
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
210 211
pl_gvFreeLayout(term_t graph_term) {
    Agraph_t *graph;
212 213
    PL_check(PL_get_graph(graph_term, &graph));
    PL_check(!gvFreeLayout(gvc, graph));
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
214 215
    PL_succeed;
}
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
216

MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
217 218 219 220
static foreign_t
pl_gvLayout(term_t graph_term, term_t engine_term) {
    Agraph_t *graph;
    char *engine;
221 222 223
    PL_check(PL_get_graph(graph_term, &graph));
    PL_check(PL_get_atom_chars(engine_term, &engine));
    PL_check(!gvLayout(gvc, graph, engine));
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
224 225
    PL_succeed;
}
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
226

MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
227
static foreign_t
228 229 230
pl_gvRenderFilename(
    term_t graph_term, term_t format_term, term_t filename_term
) {
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
231 232
    Agraph_t *graph;
    char *format;
233
    char *filename;
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
234
    FILE *file;
235 236 237 238
    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));
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
239
    PL_succeed;
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
240 241
}

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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 }
};

MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
258
install_t
259
install_graphviz_swiprolog(void) {
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
260
    gvc = gvContext();
261
    PL_register_extensions(graphviz_predicates);
MARTINEZ Thierry 's avatar
MARTINEZ Thierry committed
262
}