xref: /third_party/libabigail/src/abg-viz-dot.cc (revision e01aa904)
1// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2// -*- mode: C++ -*-
3//
4// Copyright (C) 2013-2022 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>
11ABG_BEGIN_EXPORT_DECLARATIONS
12
13#include "abg-viz-dot.h"
14
15ABG_END_EXPORT_DECLARATIONS
16// </headers defining libabigail's API>
17
18namespace abigail
19{
20
21using std::ostream;
22using std::ostringstream;
23
24// Constants.
25const style parent_sty = { color::white, color::black, "" };
26const style child_sty = { color::white, color::gray75, "" };
27
28// Define.
29units_type node_base::_M_count_total;
30
31void
32dot::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.
50void
51dot::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
67void
68dot::finish_element()
69{
70  _M_sstream << "}" << std::endl;
71}
72
73void
74dot::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
82void
83dot::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
100void
101dot::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
111void
112dot::add_parent(const parent_node& __p)
113{
114  add_node(__p);
115}
116
117void
118dot::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