1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright (C) 2013-2020 Red Hat, Inc.
5
6 #include <stdexcept>
7 #include <fstream>
8
9 #include "abg-internal.h"
10 // <headers defining libabigail's API go under here>
11 ABG_BEGIN_EXPORT_DECLARATIONS
12
13 #include "abg-viz-dot.h"
14
15 ABG_END_EXPORT_DECLARATIONS
16 // </headers defining libabigail's API>
17
18 namespace abigail
19 {
20
21 using std::ostream;
22 using std::ostringstream;
23
24 // Constants.
25 const style parent_sty = { color::white, color::black, "" };
26 const style child_sty = { color::white, color::gray75, "" };
27
28 // Define.
29 units_type node_base::_M_count_total;
30
31 void
write()32 dot::write()
33 {
34 try
35 {
36 std::string filename(_M_title + ".gv");
37 std::ofstream f(filename);
38 if (!f.is_open() || !f.good())
39 throw std::runtime_error("abigail::dot::write fail");
40
41 f << _M_sstream.str() << std::endl;
42 }
43 catch(std::exception& e)
44 {
45 throw e;
46 }
47 }
48
49 // DOT element beginning boilerplate.
50 void
start_element()51 dot::start_element()
52 {
53 // Open up digraph.
54 _M_sstream << "digraph ";
55 add_title();
56 _M_sstream << "{" << std::endl;
57
58 // Defaults.
59 // XXX typo control
60 const std::string edge_default = R"_delimiter_(edge [fontname="FreeSans",fontsize="9",labelfontname="FreeSans",labelfontsize="9"];)_delimiter_";
61 const std::string node_default = R"_delimiter_(node [fontname="FreeSans",fontsize="9",shape=record];)_delimiter_";
62
63 _M_sstream << edge_default << std::endl;
64 _M_sstream << node_default << std::endl;
65 }
66
67 void
finish_element()68 dot::finish_element()
69 {
70 _M_sstream << "}" << std::endl;
71 }
72
73 void
add_title()74 dot::add_title()
75 {
76
77 _M_sstream << '"' << _M_title << '"' << std::endl;
78 }
79
80 // See test 19, class-decl to base-class
81 // Variable: height, width
82 void
add_node(const node_base & __node)83 dot::add_node(const node_base& __node)
84 {
85 _M_sstream << "Node" << __node._M_count << " ";
86
87 const std::string label("__label");
88 const std::string height("__height");
89 const std::string width("__width");
90
91 std::string strip = R"_delimiter_([label="__label", height=__height, width=__width, color="black", fillcolor="white", style="filled"];)_delimiter_";
92
93 string_replace(strip, label, __node._M_id);
94 string_replace(strip, height, std::to_string(__node._M_y_space));
95 string_replace(strip, width, std::to_string(__node._M_x_space));
96
97 _M_sstream << strip << std::endl;
98 }
99
100 void
add_edge(const node_base & __parent,const node_base & __child)101 dot::add_edge(const node_base& __parent, const node_base& __child)
102 {
103 // XX typo control
104 std::string style = R"_delimiter_([dir="forward",color="midnightblue",fontsize="9",style="solid",fontname="FreeSans"];)_delimiter_";
105
106 _M_sstream << "Node" << __parent._M_count << "->";
107 _M_sstream << "Node" << __child._M_count;
108 _M_sstream << style << std::endl;
109 }
110
111 void
add_parent(const parent_node & __p)112 dot::add_parent(const parent_node& __p)
113 {
114 add_node(__p);
115 }
116
117 void
add_child_to_node(const child_node & __c,const node_base & __p)118 dot::add_child_to_node(const child_node& __c, const node_base& __p)
119 {
120 // XX remove duplicates
121 add_node(__c);
122 add_edge(__p, __c);
123 }
124
125 }//end namespace abigail
126