1 | #!/usr/bin/perl |
---|
2 | |
---|
3 | use strict; |
---|
4 | |
---|
5 | use XML::Parser; |
---|
6 | use IO::File; |
---|
7 | use IO::Pipe; |
---|
8 | |
---|
9 | sub genviz { |
---|
10 | my($file, $outfile)= @_; |
---|
11 | my %nodes; |
---|
12 | my $chars; |
---|
13 | my $in_node; |
---|
14 | my $in_lan; |
---|
15 | my $lan; |
---|
16 | my %links; |
---|
17 | my %lans; |
---|
18 | my $rv; |
---|
19 | my $dotfile = "/tmp/split$$.dot"; |
---|
20 | my $neato = "/usr/local/bin/neato"; |
---|
21 | my $g = new IO::File(">$dotfile") || return; |
---|
22 | my $p = new IO::Pipe() || return; |
---|
23 | my $out = new IO::File(">$outfile"); |
---|
24 | |
---|
25 | sub start_element { |
---|
26 | my($expat, $element) = @_; |
---|
27 | $in_node++ if $element eq "node"; |
---|
28 | if ( $element eq "lan" ) { |
---|
29 | $in_lan++; |
---|
30 | $lan = {}; |
---|
31 | } |
---|
32 | } |
---|
33 | |
---|
34 | sub end_element { |
---|
35 | my($expat, $element) = @_; |
---|
36 | |
---|
37 | $in_node = 0 if $element eq "node"; |
---|
38 | $nodes{$chars} = "node" if $in_node && $element eq "vname"; |
---|
39 | if ($in_lan) { |
---|
40 | if ( $element ne "lan") { |
---|
41 | $lan->{$element} = $chars if $element =~/(vname|vnode)/; |
---|
42 | } |
---|
43 | else { |
---|
44 | $in_lan = 0; |
---|
45 | my $vname = $lan->{'vname'}; |
---|
46 | if ( $links{$vname} && @{$links{$vname}} ==2 ) { |
---|
47 | # this link needs to be a lan |
---|
48 | $nodes{$vname} = "lan"; |
---|
49 | $lans{$lan->{'vname'}} = (); |
---|
50 | foreach my $l (@{$links{$vname}}) { |
---|
51 | push(@{$lans{$vname}}, $l); |
---|
52 | } |
---|
53 | push(@{$lans{$vname}}, $lan->{'vnode'}); |
---|
54 | $links{$vname} = (); |
---|
55 | $lan={}; |
---|
56 | return; |
---|
57 | } |
---|
58 | if ( $lans{$vname} && @{$lans{$vname}}) { |
---|
59 | push(@{$lans{$vname}}, $lan->{'vnode'}); |
---|
60 | $lan = {}; |
---|
61 | return; |
---|
62 | } |
---|
63 | $links{$vname} = () unless $links{$vname}; |
---|
64 | push(@{$links{$vname}}, $lan->{'vnode'}); |
---|
65 | $lan = {}; |
---|
66 | return; |
---|
67 | } |
---|
68 | } |
---|
69 | } |
---|
70 | sub found_chars { |
---|
71 | my($expat, $data) = @_; |
---|
72 | $chars = $data; |
---|
73 | } |
---|
74 | |
---|
75 | my $parser = new XML::Parser(Handlers => { |
---|
76 | Start => \&start_element, |
---|
77 | End => \&end_element, |
---|
78 | Char => \&found_chars |
---|
79 | }); |
---|
80 | |
---|
81 | print "$file\n"; |
---|
82 | $parser->parsefile($file); |
---|
83 | |
---|
84 | print $g "graph G {\n"; |
---|
85 | foreach my $n (keys %nodes) { |
---|
86 | print $g "\t$n\n"; |
---|
87 | } |
---|
88 | foreach my $l (keys %links) { |
---|
89 | print $g "\t", join(" -- ", @{$links{$l}}), "\n"; |
---|
90 | } |
---|
91 | foreach my $l (keys %lans) { |
---|
92 | foreach my $n (@{$lans{$l}}) { |
---|
93 | print $g "\t $n -- $l\n"; |
---|
94 | } |
---|
95 | } |
---|
96 | print $g "}\n"; |
---|
97 | $g->close(); |
---|
98 | $p->reader("$neato -Gstart=rand -Gepsilon=0.005 -Gmaxiter=20000 " . |
---|
99 | "-Gpack=true $dotfile"); |
---|
100 | print $out "<vis>\n"; |
---|
101 | while (<$p>) { |
---|
102 | /^\s*(\w+)\s+\[.*pos=\"(\d+),(\d+)\"/ && do { |
---|
103 | my ($n, $x, $y) = ($1, $2, $3); |
---|
104 | |
---|
105 | print "<node><name>$n</name><x>$x</x><y>$y</y><type>$nodes{$n}". |
---|
106 | "</type></node>\n" if $nodes{$n}; |
---|
107 | }; |
---|
108 | } |
---|
109 | print $out "</vis>\n"; |
---|
110 | $p->close(); |
---|
111 | unlink("$dotfile"); |
---|
112 | } |
---|
113 | |
---|
114 | genviz($ARGV[0], $ARGV[1]); |
---|