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