mutable
A Database System for Research and Fast Prototyping
Loading...
Searching...
No Matches
DotTool.cpp
Go to the documentation of this file.
2
3#include <mutable/util/fn.hpp>
5#include <fstream>
6#include <iostream>
7#include <sstream>
8
9#if __linux
10#include <dlfcn.h>
11#include <unistd.h>
12#elif __APPLE__
13#include <dlfcn.h>
14#include <unistd.h>
15#endif
16
17
18using namespace m;
19
20// POD type forward declarations
21struct GVC_t;
22struct Agraph_t;
23struct graph_t;
24
25// function declarations: add the functions that you need here and to the `SYMBOLS` X macro
26static int(*agclose)(Agraph_t*);
27static Agraph_t*(*agmemread)(const char*);
28static GVC_t*(*gvContext)();
29static int(*gvFreeContext)(GVC_t*);
30static int(*gvFreeLayout)(GVC_t*, graph_t*);
31static int(*gvLayout)(GVC_t*, graph_t*, const char*);
32static int(*gvRenderFilename)(GVC_t*, graph_t*, const char*, const char*);
33
34#define SYMBOLS(X) \
35 X(agclose) \
36 X(agmemread) \
37 X(gvContext) \
38 X(gvFreeContext) \
39 X(gvFreeLayout) \
40 X(gvLayout) \
41 X(gvRenderFilename)
42
43#define LOADSYM(SYM) SYM = (decltype(SYM))(dlsym(libgraphviz, #SYM));
44
45#if __linux
46static constexpr const char * LIB_GRAPHVIZ = "libgvc.so";
47#elif __APPLE__
48static constexpr const char * LIB_GRAPHVIZ = "libgvc.dylib";
49#endif
50
51static void *libgraphviz;
52static GVC_t *gvc;
53
55 : diag(diag)
56{
57 /*----- Test whether the graphviz library is available. ----------------------------------------------------------*/
58#if __linux || __APPLE__
59 libgraphviz = dlopen(LIB_GRAPHVIZ, RTLD_LAZY|RTLD_NOLOAD);
60 if (libgraphviz == nullptr) { // shared object not yet present; must load
61 libgraphviz = dlopen(LIB_GRAPHVIZ, RTLD_LAZY|RTLD_NODELETE); // load shared object
62
63 if (libgraphviz) {
64 /* Load the required symbols from the shared object. */
66 gvc = gvContext();
67 }
68 }
69#endif
70}
71
72int DotTool::render_to_pdf(const char *path_to_pdf, const char *algo)
73{
74 /*----- Render the dot graph with graphviz. ----------------------------------------------------------------------*/
75 auto dotstr = stream_.str();
76 Agraph_t *G = M_notnull(agmemread(dotstr.c_str()));
77 gvLayout(gvc, (graph_t*) G, algo);
78 auto ret = gvRenderFilename(gvc, (graph_t*) G, "pdf", path_to_pdf);
79 gvFreeLayout(gvc, (graph_t*) G);
80 agclose(G);
81 return ret;
82}
83
84void DotTool::show(const char *name, bool interactive, const char *algo)
85{
86 /* Construct filename. */
87 std::ostringstream oss;
88 oss << name << '_';
89#if __linux || __APPLE__
90 oss << getpid();
91#endif
92
93 /* Try to render a PDF document. */
94 if (libgraphviz) {
95 const std::string filename_pdf = oss.str() + ".pdf";
96 if (render_to_pdf(filename_pdf.c_str(), algo))
97 goto show_dot; // fall back to DOT
98
99 if (interactive) {
100#if __linux
101 exec("/usr/bin/setsid", { "--fork", "xdg-open", filename_pdf.c_str() });
102#elif __APPLE__
103 exec("/usr/bin/open", { "-a", "Preview", filename_pdf.c_str() });
104#endif
105 } else {
106 diag.out() << diag.NOTE << "Rendering to '" << filename_pdf << "'.\n" << diag.RESET;
107 }
108 return;
109 }
110
111show_dot:
112 /* Fallback: emit graph as a DOT file. */
113 const std::string filename_dot = oss.str() + ".dot";
114 std::ofstream out(filename_dot);
115 if (not out) {
116 diag.err() << "Failed to generate '" << filename_dot << "'.\n";
117 return;
118 }
119 out << stream_.rdbuf();
120 out.flush();
121 diag.out() << diag.NOTE << "Rendering to '" << filename_dot << "'.\n" << diag.RESET;
122}
#define LOADSYM(SYM)
Definition: DotTool.cpp:43
static int(* gvFreeLayout)(GVC_t *, graph_t *)
Definition: DotTool.cpp:30
static void * libgraphviz
Definition: DotTool.cpp:51
static GVC_t * gvc
Definition: DotTool.cpp:52
#define SYMBOLS(X)
Definition: DotTool.cpp:34
static int(* gvRenderFilename)(GVC_t *, graph_t *, const char *, const char *)
Definition: DotTool.cpp:32
static GVC_t *(* gvContext)()
Definition: DotTool.cpp:28
static Agraph_t *(* agmemread)(const char *)
Definition: DotTool.cpp:27
static int(* agclose)(Agraph_t *)
Definition: DotTool.cpp:26
static int(* gvFreeContext)(GVC_t *)
Definition: DotTool.cpp:29
static int(* gvLayout)(GVC_t *, graph_t *, const char *)
Definition: DotTool.cpp:31
#define M_notnull(ARG)
Definition: macro.hpp:182
‍mutable namespace
Definition: Backend.hpp:10
void M_EXPORT exec(const char *executable, std::initializer_list< const char * > args)
Definition: fn.cpp:125
static constexpr const char * NOTE
Definition: Diagnostic.hpp:16
static constexpr const char * RESET
Definition: Diagnostic.hpp:13
std::ostream & out() const
Definition: Diagnostic.hpp:52
std::ostream & err()
Definition: Diagnostic.hpp:53
void show(const char *name, bool interactive, const char *algo=DEFAULT_LAYOUT_ALGORITHM)
Present the graph to the user.
Definition: DotTool.cpp:84
int render_to_pdf(const char *path_to_pdf, const char *algo=DEFAULT_LAYOUT_ALGORITHM)
Render the graph to the PDF file path_to_pdf using the given layouting algorithm.
Definition: DotTool.cpp:72
m::Diagnostic & diag
Definition: DotTool.hpp:17
DotTool(m::Diagnostic &diag)
Definition: DotTool.cpp:54
std::stringstream stream_
Definition: DotTool.hpp:19