line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package VCG; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
6690
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
42
|
|
4
|
1
|
|
|
1
|
|
6
|
use vars qw($AUTOLOAD $VERSION $DEBUG $program); |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
77
|
|
5
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
1553
|
use IPC::Run qw(run); |
|
1
|
|
|
|
|
68701
|
|
|
1
|
|
|
|
|
1278
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
$VERSION = '0.5'; |
9
|
|
|
|
|
|
|
$DEBUG = 0; |
10
|
|
|
|
|
|
|
$program = "xvcg"; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
=head1 NAME |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
VCG - Interface to the VCG graphing tool |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
=head1 SYNOPSIS |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
use VCG; |
20
|
|
|
|
|
|
|
my $vcg = VCG->new(outfile=>'resulta.vcg'); |
21
|
|
|
|
|
|
|
$vcg->add_node(title => 'aaa'); |
22
|
|
|
|
|
|
|
$vcg->add_node(title => 'bbb', label='b'); |
23
|
|
|
|
|
|
|
$vcg->add_node(title => 'ccc', color=>'yellow'); |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
$vcg->add_edge(source => 'aaa', target=>'bbb'); |
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
$vcg->output_as_pbm('mygraph.pbm'); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
$vcg->output_as_ps(filename=>'mygraph.ps'); |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
my $data = $vcg->as_ppm(); |
32
|
|
|
|
|
|
|
open (OUTFILE, 'outfile.ppm') or die "error $!\n"; |
33
|
|
|
|
|
|
|
print OUTFILE $data; |
34
|
|
|
|
|
|
|
close OUTFILE; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 DESCRIPTION |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
This module provides an interface to to the vcg graphing tool. It supports a |
39
|
|
|
|
|
|
|
limited selection of options and file formats. The vcg graphing tool homepage |
40
|
|
|
|
|
|
|
is currently http://rw4.cs.uni-sb.de/users/sander/html/gsvcg1.html but is being actively |
41
|
|
|
|
|
|
|
developed elsewhere. |
42
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
This module is based on Leon Brocard's GraphViz module, it tries |
44
|
|
|
|
|
|
|
to provide a similar interface to offer some sense of consistency. |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
VCG is now in active development and although Graph::Writer::VCG already exists, |
47
|
|
|
|
|
|
|
this module provides a similar interface to graphviz and will be more closely tied |
48
|
|
|
|
|
|
|
into vcg as it becomes more actively developed - see James Micheal DuPont's announcement |
49
|
|
|
|
|
|
|
at http://mail.gnome.org/archives/dia-list/2003-February/msg00029.html. |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
=cut |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
=head1 METHODS |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
=head2 new |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
new objects are created using the constructor method 'new'. |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
This method accepts name attributes in the form : |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
my $vcg = VCG->new(outfile=>'foo.pbm') |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
my $vcg = VCG->new(title=>'Dia Dependancies Diagram',debug=>1); |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
my $vcg = VCG->new(); |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
my %config = ( xmax => 700, ymax=>700, program=>'xvcg', x=>30, y=>30 ); |
68
|
|
|
|
|
|
|
my $vcg = VCG->new(%config); |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
my $vcg = VCG->new( outfile=>'diagram.ps', landscape=>1, paper=>'tabloid', spline=>1 ); |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=cut |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
sub new { |
75
|
0
|
|
|
0
|
1
|
|
my $class = shift; |
76
|
0
|
|
|
|
|
|
my %config = @_; |
77
|
|
|
|
|
|
|
|
78
|
0
|
|
|
|
|
|
my $self = \%config;; |
79
|
0
|
|
|
|
|
|
bless($self, $class); |
80
|
0
|
|
|
|
|
|
$self->{edges} = []; |
81
|
0
|
|
|
|
|
|
$self->{nodes} = []; |
82
|
0
|
|
0
|
|
|
|
$self->{title} ||= "untitled"; |
83
|
0
|
|
0
|
|
|
|
$self->{outfile} ||= "vcg.out"; |
84
|
0
|
|
0
|
|
|
|
$self->{program} ||= $program; |
85
|
0
|
|
|
|
|
|
$self->{error} = "none - everything is fine"; |
86
|
|
|
|
|
|
|
|
87
|
0
|
0
|
|
|
|
|
$DEBUG = 1 if ($config{debug}); |
88
|
|
|
|
|
|
|
|
89
|
0
|
|
|
|
|
|
return $self; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
=head2 add_edge |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
add_edge allows you to add edges to your vcg object (edges are the lines or relationships between nodes). |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
In a Finite State Diagram, edges would represent transitions between states. |
97
|
|
|
|
|
|
|
|
98
|
|
|
|
|
|
|
This method accepts the source, target and colour of the edge : |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
$vcg->add_edge( source=>'from_node', target=>'to_node'); |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
$vcg->add_edge( source=>'aaa', target=>'bbb', color=>'grey'); |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=cut |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
sub add_edge { |
107
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
108
|
0
|
|
|
|
|
|
my %args = @_; |
109
|
0
|
|
0
|
|
|
|
$args{color} ||= 'black'; |
110
|
0
|
|
|
|
|
|
my $edge = qq(edge: { sourcename: "$args{source}" targetname: "$args{target}" color: $args{color}}); |
111
|
0
|
|
|
|
|
|
push (@{$self->{edges}}, $edge); |
|
0
|
|
|
|
|
|
|
112
|
0
|
|
|
|
|
|
return 1; |
113
|
|
|
|
|
|
|
} |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
=head2 add_node |
116
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
add_node allows you to add nodes to your vcg object (nodes are the things connected, while edges are the connections). |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
In a Finite State Diagram, nodes would be the individual states. |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
This method accepts the label, title and background colour of the node : |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
$vcg->add_node( title=>'aaa' ); |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
$vcg->add_node( label=>'aaa' ); |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
$vcg->add_node( label=>'aaa', title=>'A', color=>'yellow' ); |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=cut |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub add_node { |
133
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
134
|
0
|
|
|
|
|
|
my %args = @_; |
135
|
0
|
|
0
|
|
|
|
$args{color} ||= 'white'; |
136
|
0
|
|
0
|
|
|
|
$args{label} ||= $args{title}; |
137
|
0
|
|
|
|
|
|
my $node = qq(node: { title: "$args{title}" color: $args{color} label: "$args{label}"}); |
138
|
0
|
|
|
|
|
|
push (@{$self->{nodes}}, $node); |
|
0
|
|
|
|
|
|
|
139
|
0
|
|
|
|
|
|
return 1; |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
=head2 get_vcg_version |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
You can get the version and copyright message as a string using the vcg object (requires vcg be installed) |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
my $version = $vcg->get_vcg_version() or die "couldn't get version : $vcg->error() \n"; |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
=cut |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
sub get_vcg_version { |
152
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
153
|
0
|
|
|
|
|
|
my $version; |
154
|
|
|
|
|
|
|
my $error; |
155
|
0
|
|
|
|
|
|
run [$self->{program}, '-version'], \undef, \$version, \$self->{error}; |
156
|
0
|
|
|
|
|
|
return $version; |
157
|
|
|
|
|
|
|
} |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
###################################################################################### |
161
|
|
|
|
|
|
|
# generate the vcg grammar for the graph |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub _get_graph { |
164
|
0
|
|
|
0
|
|
|
my $self = shift; |
165
|
0
|
|
|
|
|
|
my $nodes = join ("\n",@{$self->{nodes}}); |
|
0
|
|
|
|
|
|
|
166
|
0
|
|
|
|
|
|
my $edges = join ("\n",@{$self->{edges}}); |
|
0
|
|
|
|
|
|
|
167
|
0
|
|
|
|
|
|
my $values = ""; |
168
|
0
|
|
|
|
|
|
foreach my $field (qw/xmax ymax x y/) { |
169
|
0
|
0
|
|
|
|
|
$values .= "$field:$self->{$field} " if ( defined $self->{$field} ); |
170
|
|
|
|
|
|
|
} |
171
|
|
|
|
|
|
|
|
172
|
0
|
|
|
|
|
|
my $graph = <
|
173
|
|
|
|
|
|
|
graph: { title: "$self->{title}" |
174
|
|
|
|
|
|
|
$values |
175
|
|
|
|
|
|
|
$nodes |
176
|
|
|
|
|
|
|
$edges |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
end |
179
|
0
|
|
|
|
|
|
return $graph; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
=head2 as_ps, as_pbm, as_ppm, as_vcg, as_plainvcg |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
The VCG object allows you to access the output of the vcg tool directly, suitable for using with graphic libraries - although some libraries or older versions may not be able to cope with these formats. |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
You can access the output in any of postscript, pbm, ppm, vcg (annotated) and vcg (plain) : |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
my $image_as_ppm = $vcg->as_ppm(); # string of image as formatted as ppm |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
my $vcg_with_coords = $vcg->as_vcg(); # handy for building a pixmap or something or converting to dia xml for example |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
=head2 output_as_ps, output_as_pbm, output_as_ppm |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
The VCG object allows you to output straight to a file through the vcg tool in any of postscript, pbm and ppm. This functionality requires that the vcg tool be installed. |
195
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
$vcg->output_as_ps('my_diagram.ps'); # now open the file in the gimp or import into LaTeX and you can get this free Mad Scientist (TM) white coat and bunsen burner. |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
=head2 output_as_vcg, output_as_plainvcg |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
The VCG object also allows you to output straight to file in annotated vcg with coordinates, or plain vcg syntax. The plain syntax does not require the vcg tool to be installed. |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
$vcg->output_as_plainvcg('compiler_graph.vcg'); # just in case you want to generate a diagram but don't have vcg installed. |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$vcg->output_as_vcg('compiler_graph_with_coords.vcg'); # lovely jubbly |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
=cut |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
###################################################################################### |
209
|
|
|
|
|
|
|
# Generate magic methods to save typing |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub AUTOLOAD { |
212
|
0
|
|
|
0
|
|
|
my $self = shift; |
213
|
0
|
0
|
|
|
|
|
my $type = ref($self) |
214
|
|
|
|
|
|
|
or die "$self is not an object"; |
215
|
|
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
my $name = $AUTOLOAD; |
217
|
0
|
|
|
|
|
|
$name =~ s/.*://; # strip fully-qualified portion |
218
|
0
|
0
|
|
|
|
|
return if $name =~ /DESTROY/; |
219
|
|
|
|
|
|
|
|
220
|
0
|
0
|
|
|
|
|
my $filename = shift() unless (scalar @_ % 2); |
221
|
0
|
|
|
|
|
|
my %args = @_; |
222
|
0
|
|
0
|
|
|
|
$filename ||= $args{filename}; |
223
|
0
|
|
0
|
|
|
|
$filename ||= $self->{outfile}; |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
my $vcg = $self->_get_graph(); |
226
|
0
|
|
|
|
|
|
my $output; |
227
|
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
|
my @vcg_args = ($filename); |
229
|
0
|
0
|
|
|
|
|
push (@vcg_args, "-scale $self->{scale}") if (defined $self->{scale}) ; |
230
|
0
|
0
|
|
|
|
|
push (@vcg_args, "-spline") if (defined $self->{spline}) ; |
231
|
0
|
0
|
|
|
|
|
push (@vcg_args, "-paper $self->{paper}") if (defined $self->{paper}) ; |
232
|
0
|
0
|
|
|
|
|
push (@vcg_args, "-portrait") if (defined $self->{portrait}) ; |
233
|
0
|
0
|
|
|
|
|
push (@vcg_args, "-landscape") if (defined $self->{landscape}) ; |
234
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
|
if ($name =~ /^as_(ps|pbm|ppm|plainvcg|vcg)/) { |
|
|
0
|
|
|
|
|
|
236
|
0
|
|
|
|
|
|
my $filetype = $1; |
237
|
0
|
|
|
|
|
|
unshift(@vcg_args,"-$filetype".'output'); |
238
|
0
|
0
|
|
|
|
|
if ($filetype eq "plainvcg") { |
239
|
0
|
|
|
|
|
|
$output = $vcg; |
240
|
|
|
|
|
|
|
} else { |
241
|
0
|
0
|
|
|
|
|
unlink $filename if (-f $filename); |
242
|
|
|
|
|
|
|
|
243
|
0
|
|
|
|
|
|
run [$self->{program}, @vcg_args , "- "], \$vcg, \$output; |
244
|
|
|
|
|
|
|
|
245
|
0
|
0
|
|
|
|
|
warn $output if ($DEBUG); |
246
|
|
|
|
|
|
|
|
247
|
0
|
0
|
|
|
|
|
open (FILE,$filename) or die "unable to open $filename : $!\n"; |
248
|
0
|
|
|
|
|
|
my $data = join ('',()); |
249
|
0
|
|
|
|
|
|
close FILE; |
250
|
0
|
0
|
|
|
|
|
if (-f $filename) { unlink $filename or die "unable to remove tempory file $filename : $! \n"; } |
|
0
|
0
|
|
|
|
|
|
251
|
0
|
|
|
|
|
|
$output = $data; |
252
|
|
|
|
|
|
|
} |
253
|
|
|
|
|
|
|
} elsif ($name =~ /output_as_(ps|pbm|ppm|plainvcg|vcg)$/){ |
254
|
0
|
|
|
|
|
|
my $filetype = $1; |
255
|
0
|
|
|
|
|
|
unshift(@vcg_args,"-$filetype".'output'); |
256
|
0
|
0
|
|
|
|
|
if ($filetype eq "plainvcg") { |
257
|
0
|
0
|
|
|
|
|
open OUTFILE,">$filename" or die "couldn't open $filename for output : $!\n"; |
258
|
0
|
|
|
|
|
|
print OUTFILE $vcg; |
259
|
0
|
|
|
|
|
|
close OUTFILE; |
260
|
0
|
|
|
|
|
|
$output = 1; |
261
|
|
|
|
|
|
|
} else { |
262
|
0
|
0
|
|
|
|
|
unlink $filename if (-f $filename); |
263
|
0
|
|
|
|
|
|
run [$self->{program}, @vcg_args , "- "], \$vcg, \$output; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
} else { |
266
|
0
|
|
|
|
|
|
die "Method $name not defined!"; |
267
|
|
|
|
|
|
|
} |
268
|
0
|
|
|
|
|
|
return $output; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
########################################################################## |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=head1 SEE ALSO |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
GraphViz : http://www.graphviz.org |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
GraphViz perl module |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
Graph::Writer::VCG perl module |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
vcg/xvcg : man pages |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 AUTHOR |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Aaron Trevena EFE |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head1 COPYRIGHT |
289
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Copyright (C) 2003, Aaron Trevena, Leon Brocard |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
This module is free software; you can redistribute it or modify it |
293
|
|
|
|
|
|
|
under the same terms as Perl itself. |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
=cut |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
########################################################################## |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
1; |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
########################################################################## |
302
|
|
|
|
|
|
|
########################################################################## |