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