aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/util/hipe_dot.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/util/hipe_dot.erl')
-rwxr-xr-xlib/hipe/util/hipe_dot.erl217
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/hipe/util/hipe_dot.erl b/lib/hipe/util/hipe_dot.erl
new file mode 100755
index 0000000000..d6ef801c88
--- /dev/null
+++ b/lib/hipe/util/hipe_dot.erl
@@ -0,0 +1,217 @@
+%%% -*- erlang-indent-level: 2 -*-
+%%%
+%%% %CopyrightBegin%
+%%%
+%%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%%%
+%%% The contents of this file are subject to the Erlang Public License,
+%%% Version 1.1, (the "License"); you may not use this file except in
+%%% compliance with the License. You should have received a copy of the
+%%% Erlang Public License along with this software. If not, it can be
+%%% retrieved online at http://www.erlang.org/.
+%%%
+%%% Software distributed under the License is distributed on an "AS IS"
+%%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%%% the License for the specific language governing rights and limitations
+%%% under the License.
+%%%
+%%% %CopyrightEnd%
+%%%
+%%%-------------------------------------------------------------------
+%%% File : hipe_dot.erl
+%%% Author : Per Gustafsson <[email protected]>
+%%% Description :
+%%%
+%%% Created : 25 Nov 2004 by Per Gustafsson <[email protected]>
+%%%-------------------------------------------------------------------
+
+-module(hipe_dot).
+
+-export([translate_digraph/3, translate_digraph/5,
+ translate_list/3, translate_list/4, translate_list/5]).
+
+%%--------------------------------------------------------------------
+
+-type gnode() :: any().
+-type edge() :: {gnode(), gnode()}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%
+%% This module creates .dot representations of graphs from their
+%% Erlang representations. There are two different forms of Erlang
+%% representations that the module accepts, digraphs and lists of two
+%% tuples (where each tuple represents a directed edge).
+%%
+%% The functions also require a FileName and a name of the graph. The
+%% filename is the name of the resulting .dot file the GraphName is
+%% pretty much useless.
+%%
+%% The resulting .dot reprsentation will be stored in the flie FileName.
+%%
+%% Interfaces:
+%%
+%% translate_list(Graph::[{Node,Node}], FileName::string(),
+%% GraphName::string()) -> ok
+%%
+%% translate_list(Graph::[{Node,Node}], FileName::string(),
+%% GraphName::string(), Options::[option] ) -> ok
+%%
+%% translate_list(Graph::[{Node,Node}], FileName::string(),
+%% GraphName::string(), Fun::fun(term() -> string()),
+%% Options::[option]) -> ok
+%%
+%% The optional Fun argument dictates how the node/names should be output.
+%%
+%% The option list can be used to pass options to .dot to decide how
+%% different nodes and edges should be displayed.
+%%
+%% translate_digraph has the same interface as translate_list except
+%% it takes a digraph rather than a list.
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-spec translate_digraph(digraph(), string(), string()) -> 'ok'.
+
+translate_digraph(G, FileName, GName) ->
+ translate_digraph(G, FileName, GName,
+ fun(X) -> io_lib:format("~p", [X]) end, []).
+
+-spec translate_digraph(digraph(), string(), string(),
+ fun((_) -> string()), [_]) -> 'ok'.
+
+translate_digraph(G, FileName, GName, Fun, Opts) ->
+ Edges = [digraph:edge(G, X) || X <- digraph:edges(G)],
+ EdgeList = [{X, Y} || {_, X, Y, _} <- Edges],
+ translate_list(EdgeList, FileName, GName, Fun, Opts).
+
+%%--------------------------------------------------------------------
+
+-spec translate_list([edge()], string(), string()) -> 'ok'.
+
+translate_list(List, FileName, GName) ->
+ translate_list(List, FileName, GName,
+ fun(X) -> lists:flatten(io_lib:format("~p", [X])) end, []).
+
+-spec translate_list([edge()], string(), string(), [_]) -> 'ok'.
+
+translate_list(List, FileName, GName, Opts) ->
+ translate_list(List, FileName, GName,
+ fun(X) -> lists:flatten(io_lib:format("~p", [X])) end, Opts).
+
+-spec translate_list([edge()], string(), string(),
+ fun((_) -> string()), [_]) -> 'ok'.
+
+translate_list(List, FileName, GName, Fun, Opts) ->
+ {NodeList1, NodeList2} = lists:unzip(List),
+ NodeList = NodeList1 ++ NodeList2,
+ NodeSet = ordsets:from_list(NodeList),
+ Start = ["digraph ",GName ," {"],
+ VertexList = [node_format(Opts, Fun, V) ||V <- NodeSet],
+ End = ["graph [", GName, "=", GName, "]}"],
+ EdgeList = [edge_format(Opts, Fun, X, Y) || {X,Y} <- List],
+ String = [Start, VertexList, EdgeList, End],
+ %% io:format("~p~n", [lists:flatten([String])]),
+ ok = file:write_file(FileName, list_to_binary(String)).
+
+%%--------------------------------------------------------------------
+
+node_format(Opt, Fun, V) ->
+ OptText = nodeoptions(Opt, Fun ,V),
+ Tmp = io_lib:format("~p", [Fun(V)]),
+ String = lists:flatten(Tmp),
+ %% io:format("~p", [String]),
+ {Width, Heigth} = calc_dim(String),
+ W = ((Width div 7) + 1) * 0.55,
+ H = Heigth * 0.4,
+ SL = io_lib:format("~f", [W]),
+ SH = io_lib:format("~f", [H]),
+ [String, " [width=", SL, " heigth=", SH, " ", OptText,"];\n"].
+
+edge_format(Opt, Fun, V1, V2) ->
+ OptText =
+ case lists:flatten(edgeoptions(Opt, Fun ,V1, V2)) of
+ [] ->
+ [];
+ [_|X] ->
+ X
+ end,
+ String = [io_lib:format("~p", [Fun(V1)]), " -> ",
+ io_lib:format("~p", [Fun(V2)])],
+ [String, " [", OptText, "];\n"].
+
+calc_dim(String) ->
+ calc_dim(String, 1, 0, 0).
+
+calc_dim("\\n" ++ T, H, TmpW, MaxW) ->
+ calc_dim(T, H+1, 0, erlang:max(TmpW, MaxW));
+calc_dim([_|T], H, TmpW, MaxW) ->
+ calc_dim(T, H, TmpW+1, MaxW);
+calc_dim([], H, TmpW, MaxW) ->
+ {erlang:max(TmpW, MaxW), H}.
+
+edgeoptions([{all_edges, {OptName, OptVal}}|T], Fun, V1, V2) ->
+ case legal_edgeoption(OptName) of
+ true ->
+ [io_lib:format(",~p=~p ", [OptName, OptVal])|edgeoptions(T, Fun, V1, V2)]
+ %% false ->
+ %% edgeoptions(T, Fun, V1, V2)
+ end;
+edgeoptions([{N1, N2, {OptName, OptVal}}|T], Fun, V1, V2) ->
+ case %% legal_edgeoption(OptName) andalso
+ Fun(N1) =:= Fun(V1) andalso Fun(N2) =:= Fun(V2) of
+ true ->
+ [io_lib:format(",~p=~p ", [OptName, OptVal])|edgeoptions(T, Fun, V1, V2)];
+ false ->
+ edgeoptions(T, Fun, V1, V2)
+ end;
+edgeoptions([_|T], Fun, V1, V2) ->
+ edgeoptions(T, Fun, V1, V2);
+edgeoptions([], _, _, _) ->
+ [].
+
+nodeoptions([{all_nodes, {OptName, OptVal}}|T], Fun, V) ->
+ case legal_nodeoption(OptName) of
+ true ->
+ [io_lib:format(",~p=~p ", [OptName, OptVal])|nodeoptions(T, Fun, V)];
+ false ->
+ nodeoptions(T, Fun, V)
+ end;
+nodeoptions([{Node, {OptName, OptVal}}|T], Fun, V) ->
+ case Fun(Node) =:= Fun(V) andalso legal_nodeoption(OptName) of
+ true ->
+ [io_lib:format("~p=~p ", [OptName, OptVal])|nodeoptions(T, Fun, V)];
+ false ->
+ nodeoptions(T, Fun, V)
+ end;
+nodeoptions([_|T], Fun, V) ->
+ nodeoptions(T, Fun, V);
+nodeoptions([], _Fun, _V) ->
+ [].
+
+legal_nodeoption(bottomlabel) -> true;
+legal_nodeoption(color) -> true;
+legal_nodeoption(comment) -> true;
+legal_nodeoption(distortion) -> true;
+legal_nodeoption(fillcolor) -> true;
+legal_nodeoption(fixedsize) -> true;
+legal_nodeoption(fontcolor) -> true;
+legal_nodeoption(fontname) -> true;
+legal_nodeoption(fontsize) -> true;
+legal_nodeoption(group) -> true;
+legal_nodeoption(height) -> true;
+legal_nodeoption(label) -> true;
+legal_nodeoption(layer) -> true;
+legal_nodeoption(orientation) -> true;
+legal_nodeoption(peripheries) -> true;
+legal_nodeoption(regular) -> true;
+legal_nodeoption(shape) -> true;
+legal_nodeoption(shapefile) -> true;
+legal_nodeoption(sides) -> true;
+legal_nodeoption(skew) -> true;
+legal_nodeoption(style) -> true;
+legal_nodeoption(toplabel) -> true;
+legal_nodeoption('URL') -> true;
+legal_nodeoption(z) -> true;
+legal_nodeoption(Option) when is_atom(Option) -> false.
+
+legal_edgeoption(Option) when is_atom(Option) -> true.