line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
############################################################################# |
2
|
|
|
|
|
|
|
# Parse VCG text into a Graph::Easy object |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
############################################################################# |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package Graph::Easy::Parser::VCG; |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
$VERSION = '0.76'; |
9
|
2
|
|
|
2
|
|
1217
|
use Graph::Easy::Parser::Graphviz; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
87
|
|
10
|
|
|
|
|
|
|
@ISA = qw/Graph::Easy::Parser::Graphviz/; |
11
|
|
|
|
|
|
|
|
12
|
2
|
|
|
2
|
|
9
|
use strict; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
33
|
|
13
|
2
|
|
|
2
|
|
6
|
use warnings; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
36
|
|
14
|
2
|
|
|
2
|
|
13
|
use utf8; |
|
2
|
|
|
|
|
2
|
|
|
2
|
|
|
|
|
6
|
|
15
|
2
|
|
|
2
|
|
30
|
use constant NO_MULTIPLES => 1; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
92
|
|
16
|
2
|
|
|
2
|
|
1023
|
use Encode qw/decode/; |
|
2
|
|
|
|
|
13461
|
|
|
2
|
|
|
|
|
6653
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub _init |
19
|
|
|
|
|
|
|
{ |
20
|
13
|
|
|
13
|
|
13
|
my $self = shift; |
21
|
|
|
|
|
|
|
|
22
|
13
|
|
|
|
|
46
|
$self->SUPER::_init(@_); |
23
|
13
|
|
|
|
|
16
|
$self->{attr_sep} = '='; |
24
|
|
|
|
|
|
|
|
25
|
13
|
|
|
|
|
27
|
$self; |
26
|
|
|
|
|
|
|
} |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
my $vcg_color_by_name = {}; |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
my $vcg_colors = [ |
31
|
|
|
|
|
|
|
white => 'white', |
32
|
|
|
|
|
|
|
blue => 'blue', |
33
|
|
|
|
|
|
|
red => 'red', |
34
|
|
|
|
|
|
|
green => 'green', |
35
|
|
|
|
|
|
|
yellow => 'yellow', |
36
|
|
|
|
|
|
|
magenta => 'magenta', |
37
|
|
|
|
|
|
|
cyan => 'cyan', |
38
|
|
|
|
|
|
|
darkgrey => 'rgb(85,85,85)', |
39
|
|
|
|
|
|
|
darkblue => 'rgb(0,0,128)', |
40
|
|
|
|
|
|
|
darkred => 'rgb(128,0,0)', |
41
|
|
|
|
|
|
|
darkgreen => 'rgb(0,128,0)', |
42
|
|
|
|
|
|
|
darkyellow => 'rgb(128,128,0)', |
43
|
|
|
|
|
|
|
darkmagenta => 'rgb(128,0,128)', |
44
|
|
|
|
|
|
|
darkcyan => 'rgb(0,128,128)', |
45
|
|
|
|
|
|
|
gold => 'rgb(255,215,0)', |
46
|
|
|
|
|
|
|
lightgrey => 'rgb(170,170,170)', |
47
|
|
|
|
|
|
|
lightblue => 'rgb(128,128,255)', |
48
|
|
|
|
|
|
|
lightred => 'rgb(255,128,128)', |
49
|
|
|
|
|
|
|
lightgreen => 'rgb(128,255,128)', |
50
|
|
|
|
|
|
|
lightyellow => 'rgb(255,255,128)', |
51
|
|
|
|
|
|
|
lightmagenta => 'rgb(255,128,255)', |
52
|
|
|
|
|
|
|
lightcyan => 'rgb(128,255,255)', |
53
|
|
|
|
|
|
|
lilac => 'rgb(238,130,238)', |
54
|
|
|
|
|
|
|
turquoise => 'rgb(64,224,208)', |
55
|
|
|
|
|
|
|
aquamarine => 'rgb(127,255,212)', |
56
|
|
|
|
|
|
|
khaki => 'rgb(240,230,140)', |
57
|
|
|
|
|
|
|
purple => 'rgb(160,32,240)', |
58
|
|
|
|
|
|
|
yellowgreen => 'rgb(154,205,50)', |
59
|
|
|
|
|
|
|
pink => 'rgb(255,192,203)', |
60
|
|
|
|
|
|
|
orange => 'rgb(255,165,0)', |
61
|
|
|
|
|
|
|
orchid => 'rgb(218,112,214)', |
62
|
|
|
|
|
|
|
black => 'black', |
63
|
|
|
|
|
|
|
]; |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
{ |
66
|
|
|
|
|
|
|
for (my $i = 0; $i < @$vcg_colors; $i+=2) |
67
|
|
|
|
|
|
|
{ |
68
|
|
|
|
|
|
|
$vcg_color_by_name->{$vcg_colors->[$i]} = $vcg_colors->[$i+1]; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub reset |
73
|
|
|
|
|
|
|
{ |
74
|
26
|
|
|
26
|
1
|
25
|
my $self = shift; |
75
|
|
|
|
|
|
|
|
76
|
26
|
|
|
|
|
46
|
Graph::Easy::Parser::reset($self, @_); |
77
|
|
|
|
|
|
|
|
78
|
26
|
|
|
|
|
27
|
my $g = $self->{_graph}; |
79
|
26
|
|
|
|
|
33
|
$self->{scope_stack} = []; |
80
|
|
|
|
|
|
|
|
81
|
26
|
|
|
|
|
30
|
$g->{_vcg_color_map} = []; |
82
|
26
|
|
|
|
|
56
|
for (my $i = 0; $i < @$vcg_colors; $i+=2) |
83
|
|
|
|
|
|
|
{ |
84
|
|
|
|
|
|
|
# set the first 32 colors as the default |
85
|
832
|
|
|
|
|
453
|
push @{$g->{_vcg_color_map}}, $vcg_colors->[$i+1]; |
|
832
|
|
|
|
|
1288
|
|
86
|
|
|
|
|
|
|
} |
87
|
|
|
|
|
|
|
|
88
|
26
|
|
|
|
|
32
|
$g->{_vcg_class_names} = {}; |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
# allow some temp. values during parsing |
91
|
26
|
|
|
|
|
149
|
$g->_allow_special_attributes( |
92
|
|
|
|
|
|
|
{ |
93
|
|
|
|
|
|
|
edge => { |
94
|
|
|
|
|
|
|
source => [ "", undef, '', '', undef, ], |
95
|
|
|
|
|
|
|
target => [ "", undef, '', '', undef, ], |
96
|
|
|
|
|
|
|
}, |
97
|
|
|
|
|
|
|
} ); |
98
|
|
|
|
|
|
|
|
99
|
26
|
|
|
|
|
30
|
$g->{_warn_on_unknown_attributes} = 1; |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
# a hack to support multiline labels |
102
|
26
|
|
|
|
|
32
|
$self->{_in_vcg_multi_line_label} = 0; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# set some default attributes on the graph object, because GDL has |
105
|
|
|
|
|
|
|
# some different defaults as Graph::Easy |
106
|
26
|
|
|
|
|
57
|
$g->set_attribute('flow', 'south'); |
107
|
26
|
|
|
|
|
37
|
$g->set_attribute('edge', 'arrow-style', 'filled'); |
108
|
26
|
|
|
|
|
44
|
$g->set_attribute('node', 'align', 'left'); |
109
|
|
|
|
|
|
|
|
110
|
26
|
|
|
|
|
32
|
$self; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub _vcg_color_map_entry |
114
|
|
|
|
|
|
|
{ |
115
|
2
|
|
|
2
|
|
3
|
my ($self, $index, $color) = @_; |
116
|
|
|
|
|
|
|
|
117
|
2
|
|
|
|
|
4
|
$color =~ /([0-9]+)\s+([0-9]+)\s+([0-9]+)/; |
118
|
2
|
|
|
|
|
9
|
$self->{_graph}->{_vcg_color_map}->[$index] = "rgb($1,$2,$3)"; |
119
|
|
|
|
|
|
|
} |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub _unquote |
122
|
|
|
|
|
|
|
{ |
123
|
81
|
|
|
81
|
|
67
|
my ($self, $name) = @_; |
124
|
|
|
|
|
|
|
|
125
|
81
|
50
|
|
|
|
104
|
$name = '' unless defined $name; |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
# "foo bar" => foo bar |
128
|
|
|
|
|
|
|
# we need to use "[ ]" here, because "\s" also matches 0x0c, and |
129
|
|
|
|
|
|
|
# these color codes need to be kept intact: |
130
|
81
|
|
|
|
|
154
|
$name =~ s/^"[ ]*//; # remove left-over quotes |
131
|
81
|
|
|
|
|
158
|
$name =~ s/[ ]*"\z//; |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
# unquote special chars |
134
|
81
|
|
|
|
|
71
|
$name =~ s/\\([\[\(\{\}\]\)#"])/$1/g; |
135
|
|
|
|
|
|
|
|
136
|
81
|
|
|
|
|
121
|
$name; |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
############################################################################# |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
sub _match_commented_line |
142
|
|
|
|
|
|
|
{ |
143
|
|
|
|
|
|
|
# matches only empty lines |
144
|
13
|
|
|
13
|
|
38
|
qr/^\s*\z/; |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub _match_multi_line_comment |
148
|
|
|
|
|
|
|
{ |
149
|
|
|
|
|
|
|
# match a multi line comment |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
# /* * comment * */ |
152
|
103
|
|
|
103
|
|
185
|
qr#^\s*/\*.*?\*/\s*#; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _match_optional_multi_line_comment |
156
|
|
|
|
|
|
|
{ |
157
|
|
|
|
|
|
|
# match a multi line comment |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# "/* * comment * */" or /* a */ /* b */ or "" |
160
|
13
|
|
|
13
|
|
23
|
qr#(?:(?:\s*/\*.*?\*/\s*)*|\s+)#; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
sub _match_classname |
164
|
|
|
|
|
|
|
{ |
165
|
|
|
|
|
|
|
# Return a regexp that matches something like classname 1: "foo" |
166
|
13
|
|
|
13
|
|
12
|
my $self = shift; |
167
|
|
|
|
|
|
|
|
168
|
13
|
|
|
|
|
22
|
qr/^\s*classname\s([0-9]+)\s*:\s*"((\\"|[^"])*)"/; |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub _match_node |
172
|
|
|
|
|
|
|
{ |
173
|
|
|
|
|
|
|
# Return a regexp that matches a node at the start of the buffer |
174
|
13
|
|
|
13
|
|
11
|
my $self = shift; |
175
|
|
|
|
|
|
|
|
176
|
13
|
|
|
|
|
27
|
my $attr = $self->_match_attributes(); |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
# Examples: "node: { title: "a" }" |
179
|
13
|
|
|
|
|
152
|
qr/^\s*node:\s*$attr/; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub _match_edge |
183
|
|
|
|
|
|
|
{ |
184
|
|
|
|
|
|
|
# Matches an edge at the start of the buffer |
185
|
13
|
|
|
13
|
|
14
|
my $self = shift; |
186
|
|
|
|
|
|
|
|
187
|
13
|
|
|
|
|
15
|
my $attr = $self->_match_attributes(); |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Examples: "edge: { sourcename: "a" targetname: "b" }" |
190
|
|
|
|
|
|
|
# "backedge: { sourcename: "a" targetname: "b" }" |
191
|
13
|
|
|
|
|
156
|
qr/^\s*(|near|bentnear|back)edge:\s*$attr/; |
192
|
|
|
|
|
|
|
} |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
sub _match_single_attribute |
195
|
|
|
|
|
|
|
{ |
196
|
|
|
|
|
|
|
|
197
|
52
|
|
|
52
|
|
84
|
qr/\s*( energetic\s\w+ # "energetic attraction" etc. |
198
|
|
|
|
|
|
|
| |
199
|
|
|
|
|
|
|
\w+ # a word |
200
|
|
|
|
|
|
|
| |
201
|
|
|
|
|
|
|
border\s(?:x|y) # "border x" or "border y" |
202
|
|
|
|
|
|
|
| |
203
|
|
|
|
|
|
|
colorentry\s+[0-9]{1,2} # colorentry |
204
|
|
|
|
|
|
|
)\s*:\s* |
205
|
|
|
|
|
|
|
( |
206
|
|
|
|
|
|
|
"(?:\\"|[^"])*" # "foo" |
207
|
|
|
|
|
|
|
| |
208
|
|
|
|
|
|
|
[0-9]{1,3}\s+[0-9]{1,3}\s+[0-9]{1,3} # "128 128 64" for color entries |
209
|
|
|
|
|
|
|
| |
210
|
|
|
|
|
|
|
\{[^\}]+\} # or {..} |
211
|
|
|
|
|
|
|
| |
212
|
|
|
|
|
|
|
[^<][^,\]\}\n\s;]* # or simple 'fooobar' |
213
|
|
|
|
|
|
|
) |
214
|
|
|
|
|
|
|
\s*/x; # possible trailing whitespace |
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
sub _match_class_attribute |
218
|
|
|
|
|
|
|
{ |
219
|
|
|
|
|
|
|
# match something like "edge.color: 10" |
220
|
|
|
|
|
|
|
|
221
|
13
|
|
|
13
|
|
18
|
qr/\s*(edge|node)\.(\w+)\s*:\s* # the attribute name (label:") |
222
|
|
|
|
|
|
|
( |
223
|
|
|
|
|
|
|
"(?:\\"|[^"])*" # "foo" |
224
|
|
|
|
|
|
|
| |
225
|
|
|
|
|
|
|
[^<][^,\]\}\n\s]* # or simple 'fooobar' |
226
|
|
|
|
|
|
|
) |
227
|
|
|
|
|
|
|
\s*/x; # possible whitespace |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub _match_attributes |
231
|
|
|
|
|
|
|
{ |
232
|
|
|
|
|
|
|
# return a regexp that matches something like " { color=red; }" and returns |
233
|
|
|
|
|
|
|
# the inner text without the {} |
234
|
|
|
|
|
|
|
|
235
|
39
|
|
|
39
|
|
41
|
my $qr_att = _match_single_attribute(); |
236
|
39
|
|
|
|
|
40
|
my $qr_cmt = _match_multi_line_comment(); |
237
|
|
|
|
|
|
|
|
238
|
39
|
|
|
|
|
301
|
qr/\s*\{\s*((?:$qr_att|$qr_cmt)*)\s*\}/; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
sub _match_graph_attribute |
242
|
|
|
|
|
|
|
{ |
243
|
|
|
|
|
|
|
# return a regexp that matches something like " color: red " for attributes |
244
|
|
|
|
|
|
|
# that apply to a graph/subgraph |
245
|
13
|
|
|
13
|
|
25
|
qr/^\s*( |
246
|
|
|
|
|
|
|
( |
247
|
|
|
|
|
|
|
colorentry\s+[0-9]{1,2}:\s+[0-9]+\s+[0-9]+\s+[0-9]+ |
248
|
|
|
|
|
|
|
| |
249
|
|
|
|
|
|
|
(?!(node|edge|nearedge|bentnearedge|graph)) # not one of these |
250
|
|
|
|
|
|
|
\w+\s*:\s*("(?:\\"|[^"])*"|[^\n\s]+) |
251
|
|
|
|
|
|
|
) |
252
|
|
|
|
|
|
|
)([\n\s]\s*|\z)/x; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
sub _clean_attributes |
256
|
|
|
|
|
|
|
{ |
257
|
51
|
|
|
51
|
|
44
|
my ($self,$text) = @_; |
258
|
|
|
|
|
|
|
|
259
|
51
|
|
|
|
|
53
|
$text =~ s/^\s*\{\s*//; # remove left-over "{" and spaces |
260
|
51
|
|
|
|
|
50
|
$text =~ s/\s*;?\s*\}\s*\z//; # remove left-over "}" and spaces |
261
|
|
|
|
|
|
|
|
262
|
51
|
|
|
|
|
66
|
$text; |
263
|
|
|
|
|
|
|
} |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
sub _match_group_end |
266
|
|
|
|
|
|
|
{ |
267
|
|
|
|
|
|
|
# return a regexp that matches something like " }" at the beginning |
268
|
13
|
|
|
13
|
|
19
|
qr/^\s*\}\s*/; |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub _match_group_start |
272
|
|
|
|
|
|
|
{ |
273
|
|
|
|
|
|
|
# return a regexp that matches something like "graph {" at the beginning |
274
|
13
|
|
|
13
|
|
17
|
qr/^\s*graph:\s+\{\s*/; |
275
|
|
|
|
|
|
|
} |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
sub _clean_line |
278
|
|
|
|
|
|
|
{ |
279
|
|
|
|
|
|
|
# do some cleanups on a line before handling it |
280
|
96
|
|
|
96
|
|
95
|
my ($self,$line) = @_; |
281
|
|
|
|
|
|
|
|
282
|
96
|
|
|
|
|
99
|
chomp($line); |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# collapse white space at start |
285
|
96
|
|
|
|
|
164
|
$line =~ s/^\s+//; |
286
|
|
|
|
|
|
|
|
287
|
96
|
100
|
|
|
|
226
|
if ($self->{_in_vcg_multi_line_label}) |
|
|
100
|
|
|
|
|
|
288
|
|
|
|
|
|
|
{ |
289
|
5
|
100
|
|
|
|
13
|
if ($line =~ /\"[^\"]*\z/) |
290
|
|
|
|
|
|
|
{ |
291
|
|
|
|
|
|
|
# '"\n' |
292
|
2
|
|
|
|
|
3
|
$self->{_in_vcg_multi_line_label} = 0; |
293
|
|
|
|
|
|
|
# restore the match stack |
294
|
2
|
|
|
|
|
2
|
$self->{match_stack} = $self->{_match_stack}; |
295
|
2
|
|
|
|
|
4
|
delete $self->{_match_stack}; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
else |
298
|
|
|
|
|
|
|
{ |
299
|
|
|
|
|
|
|
# hack: convert "a" to \"a\" to fix faulty inputs |
300
|
3
|
|
|
|
|
8
|
$line =~ s/([^\\])\"/$1\\\"/g; |
301
|
|
|
|
|
|
|
} |
302
|
|
|
|
|
|
|
} |
303
|
|
|
|
|
|
|
# a line ending in 'label: "...\n' means a multi-line label |
304
|
|
|
|
|
|
|
elsif ($line =~ /(^|\s)label:\s+\"[^\"]*\z/) |
305
|
|
|
|
|
|
|
{ |
306
|
2
|
|
|
|
|
4
|
$self->{_in_vcg_multi_line_label} = 1; |
307
|
|
|
|
|
|
|
# swap out the match stack since we just wait for the end of the label |
308
|
2
|
|
|
|
|
3
|
$self->{_match_stack} = $self->{match_stack}; |
309
|
2
|
|
|
|
|
3
|
delete $self->{match_stack}; |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
|
312
|
96
|
|
|
|
|
183
|
$line; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub _line_insert |
316
|
|
|
|
|
|
|
{ |
317
|
|
|
|
|
|
|
# What to insert between two lines. |
318
|
96
|
|
|
96
|
|
88
|
my ($self) = @_; |
319
|
|
|
|
|
|
|
|
320
|
96
|
50
|
66
|
|
|
151
|
print STDERR "in multiline\n" if $self->{_in_vcg_multi_line_label} && $self->{debug}; |
321
|
|
|
|
|
|
|
# multiline labels => '\n' |
322
|
96
|
100
|
|
|
|
141
|
return '\\n' if $self->{_in_vcg_multi_line_label}; |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
# the default is ' ' |
325
|
91
|
|
|
|
|
198
|
' '; |
326
|
|
|
|
|
|
|
} |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
############################################################################# |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
sub _new_scope |
331
|
|
|
|
|
|
|
{ |
332
|
|
|
|
|
|
|
# create a new scope, with attributes from current scope |
333
|
13
|
|
|
13
|
|
16
|
my ($self, $is_group) = @_; |
334
|
|
|
|
|
|
|
|
335
|
13
|
|
|
|
|
13
|
my $scope = {}; |
336
|
|
|
|
|
|
|
|
337
|
13
|
50
|
|
|
|
11
|
if (@{$self->{scope_stack}} > 0) |
|
13
|
|
|
|
|
25
|
|
338
|
|
|
|
|
|
|
{ |
339
|
0
|
|
|
|
|
0
|
my $old_scope = $self->{scope_stack}->[-1]; |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# make a copy of the old scope's attribtues |
342
|
0
|
|
|
|
|
0
|
for my $t (sort keys %$old_scope) |
343
|
|
|
|
|
|
|
{ |
344
|
0
|
0
|
|
|
|
0
|
next if $t =~ /^_/; |
345
|
0
|
|
|
|
|
0
|
my $s = $old_scope->{$t}; |
346
|
0
|
0
|
|
|
|
0
|
$scope->{$t} = {} unless ref $scope->{$t}; my $sc = $scope->{$t}; |
|
0
|
|
|
|
|
0
|
|
347
|
0
|
|
|
|
|
0
|
for my $k (sort keys %$s) |
348
|
|
|
|
|
|
|
{ |
349
|
|
|
|
|
|
|
# skip things like "_is_group" |
350
|
0
|
0
|
|
|
|
0
|
$sc->{$k} = $s->{$k} unless $k =~ /^_/; |
351
|
|
|
|
|
|
|
} |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
} |
354
|
13
|
50
|
|
|
|
31
|
$scope->{_is_group} = 1 if defined $is_group; |
355
|
|
|
|
|
|
|
|
356
|
13
|
|
|
|
|
14
|
push @{$self->{scope_stack}}, $scope; |
|
13
|
|
|
|
|
18
|
|
357
|
|
|
|
|
|
|
|
358
|
13
|
|
|
|
|
15
|
$scope; |
359
|
|
|
|
|
|
|
} |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub _edge_style |
362
|
|
|
|
|
|
|
{ |
363
|
|
|
|
|
|
|
# To convert "--" or "->" we simple do nothing, since the edge style in |
364
|
|
|
|
|
|
|
# VCG can only be set via the attributes (if at all) |
365
|
0
|
|
|
0
|
|
0
|
my ($self, $ed) = @_; |
366
|
|
|
|
|
|
|
|
367
|
0
|
|
|
|
|
0
|
'solid'; |
368
|
|
|
|
|
|
|
} |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub _build_match_stack |
371
|
|
|
|
|
|
|
{ |
372
|
13
|
|
|
13
|
|
11
|
my $self = shift; |
373
|
|
|
|
|
|
|
|
374
|
13
|
|
|
|
|
23
|
my $qr_cn = $self->_match_classname(); |
375
|
13
|
|
|
|
|
21
|
my $qr_node = $self->_match_node(); |
376
|
13
|
|
|
|
|
24
|
my $qr_cmt = $self->_match_multi_line_comment(); |
377
|
13
|
|
|
|
|
22
|
my $qr_ocmt = $self->_match_optional_multi_line_comment(); |
378
|
13
|
|
|
|
|
26
|
my $qr_attr = $self->_match_attributes(); |
379
|
13
|
|
|
|
|
21
|
my $qr_gatr = $self->_match_graph_attribute(); |
380
|
13
|
|
|
|
|
36
|
my $qr_oatr = $self->_match_optional_attributes(); |
381
|
13
|
|
|
|
|
26
|
my $qr_edge = $self->_match_edge(); |
382
|
13
|
|
|
|
|
25
|
my $qr_class = $self->_match_class_attribute(); |
383
|
|
|
|
|
|
|
|
384
|
13
|
|
|
|
|
28
|
my $qr_group_end = $self->_match_group_end(); |
385
|
13
|
|
|
|
|
23
|
my $qr_group_start = $self->_match_group_start(); |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# "graph: {" |
388
|
|
|
|
|
|
|
$self->_register_handler( $qr_group_start, |
389
|
|
|
|
|
|
|
sub |
390
|
|
|
|
|
|
|
{ |
391
|
13
|
|
|
13
|
|
15
|
my $self = shift; |
392
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
# the main graph |
394
|
13
|
50
|
|
|
|
10
|
if (@{$self->{scope_stack}} == 0) |
|
13
|
|
|
|
|
23
|
|
395
|
|
|
|
|
|
|
{ |
396
|
13
|
50
|
|
|
|
23
|
print STDERR "# Parser: found main graph\n" if $self->{debug}; |
397
|
13
|
|
|
|
|
31
|
$self->{_vcg_graph_name} = 'unnamed'; |
398
|
13
|
|
|
|
|
22
|
$self->_new_scope(1); |
399
|
|
|
|
|
|
|
} |
400
|
|
|
|
|
|
|
else |
401
|
|
|
|
|
|
|
{ |
402
|
0
|
0
|
|
|
|
0
|
print STDERR "# Parser: found subgraph\n" if $self->{debug}; |
403
|
|
|
|
|
|
|
# a new subgraph |
404
|
0
|
|
|
|
|
0
|
push @{$self->{group_stack}}, $self->_new_group(); |
|
0
|
|
|
|
|
0
|
|
405
|
|
|
|
|
|
|
} |
406
|
13
|
|
|
|
|
18
|
1; |
407
|
13
|
|
|
|
|
87
|
} ); |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
# graph or subgraph end "}" |
410
|
|
|
|
|
|
|
$self->_register_handler( $qr_group_end, |
411
|
|
|
|
|
|
|
sub |
412
|
|
|
|
|
|
|
{ |
413
|
13
|
|
|
13
|
|
12
|
my $self = shift; |
414
|
|
|
|
|
|
|
|
415
|
13
|
50
|
|
|
|
22
|
print STDERR "# Parser: found end of (sub-)graph\n" if $self->{debug}; |
416
|
|
|
|
|
|
|
|
417
|
13
|
|
|
|
|
9
|
my $scope = pop @{$self->{scope_stack}}; |
|
13
|
|
|
|
|
19
|
|
418
|
13
|
50
|
|
|
|
18
|
return $self->parse_error(0) if !defined $scope; |
419
|
|
|
|
|
|
|
|
420
|
13
|
|
|
|
|
32
|
1; |
421
|
13
|
|
|
|
|
40
|
} ); |
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
# classname 1: "foo" |
424
|
|
|
|
|
|
|
$self->_register_handler( $qr_cn, |
425
|
|
|
|
|
|
|
sub { |
426
|
2
|
|
|
2
|
|
3
|
my $self = shift; |
427
|
2
|
|
|
|
|
3
|
my $class = $1; my $name = $2; |
|
2
|
|
|
|
|
1
|
|
428
|
|
|
|
|
|
|
|
429
|
2
|
50
|
|
|
|
5
|
print STDERR "# Found classname '$name' for class '$class'\n" if $self->{debug} > 1; |
430
|
|
|
|
|
|
|
|
431
|
2
|
|
|
|
|
2
|
$self->{_graph}->{_vcg_class_names}->{$class} = $name; |
432
|
2
|
|
|
|
|
3
|
1; |
433
|
13
|
|
|
|
|
39
|
} ); |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
# node: { ... } |
436
|
|
|
|
|
|
|
$self->_register_handler( $qr_node, |
437
|
|
|
|
|
|
|
sub { |
438
|
26
|
|
|
26
|
|
26
|
my $self = shift; |
439
|
26
|
|
50
|
|
|
98
|
my $att = $self->_parse_attributes($1 || '', 'node', NO_MULTIPLES ); |
440
|
26
|
50
|
|
|
|
41
|
return undef unless defined $att; # error in attributes? |
441
|
|
|
|
|
|
|
|
442
|
26
|
|
|
|
|
30
|
my $name = $att->{title}; delete $att->{title}; |
|
26
|
|
|
|
|
32
|
|
443
|
|
|
|
|
|
|
|
444
|
26
|
50
|
|
|
|
48
|
print STDERR "# Found node with name $name\n" if $self->{debug} > 1; |
445
|
|
|
|
|
|
|
|
446
|
26
|
|
|
|
|
66
|
my $node = $self->_new_node($self->{_graph}, $name, $self->{group_stack}, $att, []); |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# set attributes from scope |
449
|
26
|
|
50
|
|
|
53
|
my $scope = $self->{scope_stack}->[-1] || {}; |
450
|
26
|
100
|
|
|
|
21
|
$node->set_attributes ($scope->{node}) if keys %{$scope->{node}} != 0; |
|
26
|
|
|
|
|
73
|
|
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
# override with local attributes |
453
|
26
|
100
|
|
|
|
62
|
$node->set_attributes ($att) if keys %$att != 0; |
454
|
26
|
|
|
|
|
49
|
1; |
455
|
13
|
|
|
|
|
45
|
} ); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# "edge: { ... }" |
458
|
|
|
|
|
|
|
$self->_register_handler( $qr_edge, |
459
|
|
|
|
|
|
|
sub { |
460
|
13
|
|
|
13
|
|
12
|
my $self = shift; |
461
|
13
|
|
50
|
|
|
60
|
my $type = $1 || 'edge'; |
462
|
13
|
|
50
|
|
|
33
|
my $txt = $2 || ''; |
463
|
13
|
50
|
|
|
|
31
|
$type = "edge" if $type =~ /edge/; # bentnearedge => edge |
464
|
13
|
|
|
|
|
45
|
my $att = $self->_parse_attributes($txt, 'edge', NO_MULTIPLES ); |
465
|
13
|
50
|
|
|
|
24
|
return undef unless defined $att; # error in attributes? |
466
|
|
|
|
|
|
|
|
467
|
13
|
|
|
|
|
16
|
my $from = $att->{source}; delete $att->{source}; |
|
13
|
|
|
|
|
14
|
|
468
|
13
|
|
|
|
|
13
|
my $to = $att->{target}; delete $att->{target}; |
|
13
|
|
|
|
|
8
|
|
469
|
|
|
|
|
|
|
|
470
|
13
|
50
|
|
|
|
30
|
print STDERR "# Found edge ($type) from $from to $to\n" if $self->{debug} > 1; |
471
|
|
|
|
|
|
|
|
472
|
13
|
|
|
|
|
33
|
my $edge = $self->{_graph}->add_edge ($from, $to); |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
# set attributes from scope |
475
|
13
|
|
50
|
|
|
26
|
my $scope = $self->{scope_stack}->[-1] || {}; |
476
|
13
|
100
|
|
|
|
9
|
$edge->set_attributes ($scope->{edge}) if keys %{$scope->{edge}} != 0; |
|
13
|
|
|
|
|
37
|
|
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
# override with local attributes |
479
|
13
|
100
|
|
|
|
29
|
$edge->set_attributes ($att) if keys %$att != 0; |
480
|
|
|
|
|
|
|
|
481
|
13
|
|
|
|
|
26
|
1; |
482
|
13
|
|
|
|
|
48
|
} ); |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
# color: red (for graphs or subgraphs) |
485
|
13
|
|
|
|
|
121
|
$self->_register_attribute_handler($qr_gatr, 'parent'); |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
# edge.color: 10 |
488
|
|
|
|
|
|
|
$self->_register_handler( $qr_class, |
489
|
|
|
|
|
|
|
sub { |
490
|
6
|
|
|
6
|
|
7
|
my $self = shift; |
491
|
6
|
|
|
|
|
10
|
my $type = $1; |
492
|
6
|
|
|
|
|
7
|
my $name = $2; |
493
|
6
|
|
|
|
|
7
|
my $val = $3; |
494
|
|
|
|
|
|
|
|
495
|
6
|
50
|
|
|
|
10
|
print STDERR "# Found color definition $type $name $val\n" if $self->{debug} > 2; |
496
|
|
|
|
|
|
|
|
497
|
6
|
|
|
|
|
19
|
my $att = $self->_remap_attributes( { $name => $val }, $type, $self->_remap()); |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
# store the attributes in the current scope |
500
|
6
|
|
|
|
|
8
|
my $scope = $self->{scope_stack}->[-1]; |
501
|
6
|
100
|
|
|
|
13
|
$scope->{$type} = {} unless ref $scope->{$type}; |
502
|
6
|
|
|
|
|
6
|
my $s = $scope->{$type}; |
503
|
|
|
|
|
|
|
|
504
|
6
|
|
|
|
|
9
|
for my $k (sort keys %$att) |
505
|
|
|
|
|
|
|
{ |
506
|
6
|
|
|
|
|
7
|
$s->{$k} = $att->{$k}; |
507
|
|
|
|
|
|
|
} |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
#$self->{_graph}->set_attributes ($type, $att); |
510
|
6
|
|
|
|
|
13
|
1; |
511
|
13
|
|
|
|
|
60
|
}); |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
# remove multi line comments /* comment */ |
514
|
13
|
|
|
|
|
21
|
$self->_register_handler( $qr_cmt, undef ); |
515
|
|
|
|
|
|
|
|
516
|
|
|
|
|
|
|
# remove single line comment // comment |
517
|
13
|
|
|
|
|
31
|
$self->_register_handler( qr/^\s*\/\/.*/, undef ); |
518
|
|
|
|
|
|
|
|
519
|
13
|
|
|
|
|
28
|
$self; |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
sub _new_node |
523
|
|
|
|
|
|
|
{ |
524
|
|
|
|
|
|
|
# add a node to the graph, overridable by subclasses |
525
|
26
|
|
|
26
|
|
30
|
my ($self, $graph, $name, $group_stack, $att, $stack) = @_; |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
# print STDERR "add_node $name\n"; |
528
|
|
|
|
|
|
|
|
529
|
26
|
|
|
|
|
49
|
my $node = $graph->node($name); |
530
|
|
|
|
|
|
|
|
531
|
26
|
50
|
|
|
|
36
|
if (!defined $node) |
532
|
|
|
|
|
|
|
{ |
533
|
26
|
|
|
|
|
55
|
$node = $graph->add_node($name); # add |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
# apply attributes from the current scope (only for new nodes) |
536
|
26
|
|
|
|
|
31
|
my $scope = $self->{scope_stack}->[-1]; |
537
|
26
|
50
|
|
|
|
50
|
return $self->error("Scope stack is empty!") unless defined $scope; |
538
|
|
|
|
|
|
|
|
539
|
26
|
|
|
|
|
27
|
my $is_group = $scope->{_is_group}; |
540
|
26
|
|
|
|
|
22
|
delete $scope->{_is_group}; |
541
|
26
|
|
|
|
|
63
|
$node->set_attributes($scope->{node}); |
542
|
26
|
50
|
|
|
|
51
|
$scope->{_is_group} = $is_group if $is_group; |
543
|
|
|
|
|
|
|
|
544
|
26
|
|
|
|
|
25
|
my $group = $self->{group_stack}->[-1]; |
545
|
|
|
|
|
|
|
|
546
|
26
|
50
|
|
|
|
43
|
$node->add_to_group($group) if $group; |
547
|
|
|
|
|
|
|
} |
548
|
|
|
|
|
|
|
|
549
|
26
|
|
|
|
|
73
|
$node; |
550
|
|
|
|
|
|
|
} |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
############################################################################# |
553
|
|
|
|
|
|
|
# attribute remapping |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
# undef => drop that attribute |
556
|
|
|
|
|
|
|
# not listed attributes are simple copied unmodified |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
my $vcg_remap = { |
559
|
|
|
|
|
|
|
'node' => { |
560
|
|
|
|
|
|
|
iconfile => 'x-vcg-iconfile', |
561
|
|
|
|
|
|
|
info1 => 'x-vcg-info1', |
562
|
|
|
|
|
|
|
info2 => 'x-vcg-info2', |
563
|
|
|
|
|
|
|
info3 => 'x-vcg-info3', |
564
|
|
|
|
|
|
|
invisible => \&_invisible_from_vcg, |
565
|
|
|
|
|
|
|
importance => 'x-vcg-importance', |
566
|
|
|
|
|
|
|
focus => 'x-vcg-focus', |
567
|
|
|
|
|
|
|
margin => 'x-vcg-margin', |
568
|
|
|
|
|
|
|
textmode => \&_textmode_from_vcg, |
569
|
|
|
|
|
|
|
textcolor => \&_node_color_from_vcg, |
570
|
|
|
|
|
|
|
color => \&_node_color_from_vcg, |
571
|
|
|
|
|
|
|
bordercolor => \&_node_color_from_vcg, |
572
|
|
|
|
|
|
|
level => 'rank', |
573
|
|
|
|
|
|
|
horizontal_order => \&_horizontal_order_from_vcg, |
574
|
|
|
|
|
|
|
shape => \&_vcg_node_shape, |
575
|
|
|
|
|
|
|
vertical_order => \&_vertical_order_from_vcg, |
576
|
|
|
|
|
|
|
}, |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
'edge' => { |
579
|
|
|
|
|
|
|
anchor => 'x-vcg-anchor', |
580
|
|
|
|
|
|
|
right_anchor => 'x-vcg-right_anchor', |
581
|
|
|
|
|
|
|
left_anchor => 'x-vcg-left_anchor', |
582
|
|
|
|
|
|
|
arrowcolor => 'x-vcg-arrowcolor', |
583
|
|
|
|
|
|
|
arrowsize => 'x-vcg-arrowsize', |
584
|
|
|
|
|
|
|
# XXX remap this |
585
|
|
|
|
|
|
|
arrowstyle => 'x-vcg-arrowstyle', |
586
|
|
|
|
|
|
|
backarrowcolor => 'x-vcg-backarrowcolor', |
587
|
|
|
|
|
|
|
backarrowsize => 'x-vcg-backarrowsize', |
588
|
|
|
|
|
|
|
backarrowstyle => 'x-vcg-backarrowstyle', |
589
|
|
|
|
|
|
|
class => \&_edge_class_from_vcg, |
590
|
|
|
|
|
|
|
color => \&_edge_color_from_vcg, |
591
|
|
|
|
|
|
|
horizontal_order => 'x-vcg-horizontal_order', |
592
|
|
|
|
|
|
|
linestyle => 'style', |
593
|
|
|
|
|
|
|
priority => 'x-vcg-priority', |
594
|
|
|
|
|
|
|
source => 'source', |
595
|
|
|
|
|
|
|
sourcename => 'source', |
596
|
|
|
|
|
|
|
target => 'target', |
597
|
|
|
|
|
|
|
targetname => 'target', |
598
|
|
|
|
|
|
|
textcolor => \&_edge_color_from_vcg, |
599
|
|
|
|
|
|
|
thickness => 'x-vcg-thickness', # remap to broad etc. |
600
|
|
|
|
|
|
|
}, |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
'graph' => { |
603
|
|
|
|
|
|
|
color => \&_node_color_from_vcg, |
604
|
|
|
|
|
|
|
bordercolor => \&_node_color_from_vcg, |
605
|
|
|
|
|
|
|
textcolor => \&_node_color_from_vcg, |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
x => 'x-vcg-x', |
608
|
|
|
|
|
|
|
y => 'x-vcg-y', |
609
|
|
|
|
|
|
|
xmax => 'x-vcg-xmax', |
610
|
|
|
|
|
|
|
ymax => 'x-vcg-ymax', |
611
|
|
|
|
|
|
|
xspace => 'x-vcg-xspace', |
612
|
|
|
|
|
|
|
yspace => 'x-vcg-yspace', |
613
|
|
|
|
|
|
|
xlspace => 'x-vcg-xlspace', |
614
|
|
|
|
|
|
|
ylspace => 'x-vcg-ylspace', |
615
|
|
|
|
|
|
|
xbase => 'x-vcg-xbase', |
616
|
|
|
|
|
|
|
ybase => 'x-vcg-ybase', |
617
|
|
|
|
|
|
|
xlraster => 'x-vcg-xlraster', |
618
|
|
|
|
|
|
|
xraster => 'x-vcg-xraster', |
619
|
|
|
|
|
|
|
yraster => 'x-vcg-yraster', |
620
|
|
|
|
|
|
|
|
621
|
|
|
|
|
|
|
amax => 'x-vcg-amax', |
622
|
|
|
|
|
|
|
bmax => 'x-vcg-bmax', |
623
|
|
|
|
|
|
|
cmax => 'x-vcg-cmax', |
624
|
|
|
|
|
|
|
cmin => 'x-vcg-cmin', |
625
|
|
|
|
|
|
|
smax => 'x-vcg-smax', |
626
|
|
|
|
|
|
|
pmax => 'x-vcg-pmax', |
627
|
|
|
|
|
|
|
pmin => 'x-vcg-pmin', |
628
|
|
|
|
|
|
|
rmax => 'x-vcg-rmax', |
629
|
|
|
|
|
|
|
rmin => 'x-vcg-rmin', |
630
|
|
|
|
|
|
|
|
631
|
|
|
|
|
|
|
splines => 'x-vcg-splines', |
632
|
|
|
|
|
|
|
focus => 'x-vcg-focus', |
633
|
|
|
|
|
|
|
hidden => 'x-vcg-hidden', |
634
|
|
|
|
|
|
|
horizontal_order => 'x-vcg-horizontal_order', |
635
|
|
|
|
|
|
|
iconfile => 'x-vcg-iconfile', |
636
|
|
|
|
|
|
|
inport_sharing => \&_inport_sharing_from_vcg, |
637
|
|
|
|
|
|
|
importance => 'x-vcg-importance', |
638
|
|
|
|
|
|
|
ignore_singles => 'x-vcg-ignore_singles', |
639
|
|
|
|
|
|
|
invisible => 'x-vcg-invisible', |
640
|
|
|
|
|
|
|
info1 => 'x-vcg-info1', |
641
|
|
|
|
|
|
|
info2 => 'x-vcg-info2', |
642
|
|
|
|
|
|
|
info3 => 'x-vcg-info3', |
643
|
|
|
|
|
|
|
infoname1 => 'x-vcg-infoname1', |
644
|
|
|
|
|
|
|
infoname2 => 'x-vcg-infoname2', |
645
|
|
|
|
|
|
|
infoname3 => 'x-vcg-infoname3', |
646
|
|
|
|
|
|
|
level => 'x-vcg-level', |
647
|
|
|
|
|
|
|
loc => 'x-vcg-loc', |
648
|
|
|
|
|
|
|
layout_algorithm => 'x-vcg-layout_algorithm', |
649
|
|
|
|
|
|
|
# also allow this variant: |
650
|
|
|
|
|
|
|
layoutalgorithm => 'x-vcg-layout_algorithm', |
651
|
|
|
|
|
|
|
layout_downfactor => 'x-vcg-layout_downfactor', |
652
|
|
|
|
|
|
|
layout_upfactor => 'x-vcg-layout_upfactor', |
653
|
|
|
|
|
|
|
layout_nearfactor => 'x-vcg-layout_nearfactor', |
654
|
|
|
|
|
|
|
linear_segments => 'x-vcg-linear_segments', |
655
|
|
|
|
|
|
|
margin => 'x-vcg-margin', |
656
|
|
|
|
|
|
|
manhattan_edges => \&_manhattan_edges_from_vcg, |
657
|
|
|
|
|
|
|
near_edges => 'x-vcg-near_edges', |
658
|
|
|
|
|
|
|
nearedges => 'x-vcg-nearedges', |
659
|
|
|
|
|
|
|
node_alignment => 'x-vcg-node_alignment', |
660
|
|
|
|
|
|
|
port_sharing => \&_port_sharing_from_vcg, |
661
|
|
|
|
|
|
|
priority_phase => 'x-vcg-priority_phase', |
662
|
|
|
|
|
|
|
outport_sharing => \&_outport_sharing_from_vcg, |
663
|
|
|
|
|
|
|
shape => 'x-vcg-shape', |
664
|
|
|
|
|
|
|
smanhattan_edges => 'x-vcg-smanhattan_edges', |
665
|
|
|
|
|
|
|
state => 'x-vcg-state', |
666
|
|
|
|
|
|
|
splines => 'x-vcg-splines', |
667
|
|
|
|
|
|
|
splinefactor => 'x-vcg-splinefactor', |
668
|
|
|
|
|
|
|
spreadlevel => 'x-vcg-spreadlevel', |
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
title => 'label', |
671
|
|
|
|
|
|
|
textmode => \&_textmode_from_vcg, |
672
|
|
|
|
|
|
|
useractioncmd1 => 'x-vcg-useractioncmd1', |
673
|
|
|
|
|
|
|
useractioncmd2 => 'x-vcg-useractioncmd2', |
674
|
|
|
|
|
|
|
useractioncmd3 => 'x-vcg-useractioncmd3', |
675
|
|
|
|
|
|
|
useractioncmd4 => 'x-vcg-useractioncmd4', |
676
|
|
|
|
|
|
|
useractionname1 => 'x-vcg-useractionname1', |
677
|
|
|
|
|
|
|
useractionname2 => 'x-vcg-useractionname2', |
678
|
|
|
|
|
|
|
useractionname3 => 'x-vcg-useractionname3', |
679
|
|
|
|
|
|
|
useractionname4 => 'x-vcg-useractionname4', |
680
|
|
|
|
|
|
|
vertical_order => 'x-vcg-vertical_order', |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
display_edge_labels => 'x-vcg-display_edge_labels', |
683
|
|
|
|
|
|
|
edges => 'x-vcg-edges', |
684
|
|
|
|
|
|
|
nodes => 'x-vcg-nodes', |
685
|
|
|
|
|
|
|
icons => 'x-vcg-icons', |
686
|
|
|
|
|
|
|
iconcolors => 'x-vcg-iconcolors', |
687
|
|
|
|
|
|
|
view => 'x-vcg-view', |
688
|
|
|
|
|
|
|
subgraph_labels => 'x-vcg-subgraph_labels', |
689
|
|
|
|
|
|
|
arrow_mode => 'x-vcg-arrow_mode', |
690
|
|
|
|
|
|
|
arrowmode => 'x-vcg-arrowmode', |
691
|
|
|
|
|
|
|
crossing_optimization => 'x-vcg-crossing_optimization', |
692
|
|
|
|
|
|
|
crossing_phase2 => 'x-vcg-crossing_phase2', |
693
|
|
|
|
|
|
|
crossing_weight => 'x-vcg-crossing_weight', |
694
|
|
|
|
|
|
|
equal_y_dist => 'x-vcg-equal_y_dist', |
695
|
|
|
|
|
|
|
equalydist => 'x-vcg-equalydist', |
696
|
|
|
|
|
|
|
finetuning => 'x-vcg-finetuning', |
697
|
|
|
|
|
|
|
fstraight_phase => 'x-vcg-fstraight_phase', |
698
|
|
|
|
|
|
|
straight_phase => 'x-vcg-straight_phase', |
699
|
|
|
|
|
|
|
import_sharing => 'x-vcg-import_sharing', |
700
|
|
|
|
|
|
|
late_edge_labels => 'x-vcg-late_edge_labels', |
701
|
|
|
|
|
|
|
treefactor => 'x-vcg-treefactor', |
702
|
|
|
|
|
|
|
orientation => \&_orientation_from_vcg, |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
attraction => 'x-vcg-attraction', |
705
|
|
|
|
|
|
|
'border x' => 'x-vcg-border-x', |
706
|
|
|
|
|
|
|
'border y' => 'x-vcg-border-y', |
707
|
|
|
|
|
|
|
'energetic' => 'x-vcg-energetic', |
708
|
|
|
|
|
|
|
'energetic attraction' => 'x-vcg-energetic-attraction', |
709
|
|
|
|
|
|
|
'energetic border' => 'x-vcg-energetic-border', |
710
|
|
|
|
|
|
|
'energetic crossing' => 'x-vcg-energetic-crossing', |
711
|
|
|
|
|
|
|
'energetic gravity' => 'x-vcg-energetic gravity', |
712
|
|
|
|
|
|
|
'energetic overlapping' => 'x-vcg-energetic overlapping', |
713
|
|
|
|
|
|
|
'energetic repulsion' => 'x-vcg-energetic repulsion', |
714
|
|
|
|
|
|
|
fdmax => 'x-vcg-fdmax', |
715
|
|
|
|
|
|
|
gravity => 'x-vcg-gravity', |
716
|
|
|
|
|
|
|
|
717
|
|
|
|
|
|
|
magnetic_field1 => 'x-vcg-magnetic_field1', |
718
|
|
|
|
|
|
|
magnetic_field2 => 'x-vcg-magnetic_field2', |
719
|
|
|
|
|
|
|
magnetic_force1 => 'x-vcg-magnetic_force1', |
720
|
|
|
|
|
|
|
magnetic_force2 => 'x-vcg-magnetic_force2', |
721
|
|
|
|
|
|
|
randomfactor => 'x-vcg-randomfactor', |
722
|
|
|
|
|
|
|
randomimpulse => 'x-vcg-randomimpulse', |
723
|
|
|
|
|
|
|
randomrounds => 'x-vcg-randomrounds', |
724
|
|
|
|
|
|
|
repulsion => 'x-vcg-repulsion', |
725
|
|
|
|
|
|
|
tempfactor => 'x-vcg-tempfactor', |
726
|
|
|
|
|
|
|
tempmax => 'x-vcg-tempmax', |
727
|
|
|
|
|
|
|
tempmin => 'x-vcg-tempmin'. |
728
|
|
|
|
|
|
|
tempscheme => 'x-vcg-tempscheme'. |
729
|
|
|
|
|
|
|
temptreshold => 'x-vcg-temptreshold', |
730
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
dirty_edge_labels => 'x-vcg-dirty_edge_labels', |
732
|
|
|
|
|
|
|
fast_icons => 'x-vcg-fast_icons', |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
}, |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
'group' => { |
737
|
|
|
|
|
|
|
# graph attributes will be added here automatically |
738
|
|
|
|
|
|
|
title => \&_group_name_from_vcg, |
739
|
|
|
|
|
|
|
status => 'x-vcg-status', |
740
|
|
|
|
|
|
|
}, |
741
|
|
|
|
|
|
|
|
742
|
|
|
|
|
|
|
'all' => { |
743
|
|
|
|
|
|
|
loc => 'x-vcg-loc', |
744
|
|
|
|
|
|
|
folding => 'x-vcg-folding', |
745
|
|
|
|
|
|
|
scaling => 'x-vcg-scaling', |
746
|
|
|
|
|
|
|
shrink => 'x-vcg-shrink', |
747
|
|
|
|
|
|
|
stretch => 'x-vcg-stretch', |
748
|
|
|
|
|
|
|
width => 'x-vcg-width', |
749
|
|
|
|
|
|
|
height => 'x-vcg-height', |
750
|
|
|
|
|
|
|
fontname => 'font', |
751
|
|
|
|
|
|
|
}, |
752
|
|
|
|
|
|
|
}; |
753
|
|
|
|
|
|
|
|
754
|
|
|
|
|
|
|
{ |
755
|
|
|
|
|
|
|
# add all graph attributes to group, too |
756
|
|
|
|
|
|
|
my $group = $vcg_remap->{group}; |
757
|
|
|
|
|
|
|
my $graph = $vcg_remap->{graph}; |
758
|
|
|
|
|
|
|
for my $k (sort keys %$graph) |
759
|
|
|
|
|
|
|
{ |
760
|
|
|
|
|
|
|
$group->{$k} = $graph->{$k}; |
761
|
|
|
|
|
|
|
} |
762
|
|
|
|
|
|
|
} |
763
|
|
|
|
|
|
|
|
764
|
57
|
|
|
57
|
|
74
|
sub _remap { $vcg_remap; } |
765
|
|
|
|
|
|
|
|
766
|
|
|
|
|
|
|
my $vcg_edge_color_remap = { |
767
|
|
|
|
|
|
|
textcolor => 'labelcolor', |
768
|
|
|
|
|
|
|
}; |
769
|
|
|
|
|
|
|
|
770
|
|
|
|
|
|
|
my $vcg_node_color_remap = { |
771
|
|
|
|
|
|
|
textcolor => 'color', |
772
|
|
|
|
|
|
|
color => 'fill', |
773
|
|
|
|
|
|
|
}; |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub _vertical_order_from_vcg |
776
|
|
|
|
|
|
|
{ |
777
|
|
|
|
|
|
|
# remap "vertical_order: 5" to "rank: 5" |
778
|
1
|
|
|
1
|
|
2
|
my ($graph, $name, $value) = @_; |
779
|
|
|
|
|
|
|
|
780
|
1
|
|
|
|
|
1
|
my $rank = $value; |
781
|
|
|
|
|
|
|
# insert a really really high rank |
782
|
1
|
50
|
|
|
|
3
|
$rank = '1000000' if $value eq 'maxdepth'; |
783
|
|
|
|
|
|
|
|
784
|
|
|
|
|
|
|
# save the original value, too |
785
|
1
|
|
|
|
|
3
|
('x-vcg-vertical_order', $value, 'rank', $rank); |
786
|
|
|
|
|
|
|
} |
787
|
|
|
|
|
|
|
|
788
|
|
|
|
|
|
|
sub _horizontal_order_from_vcg |
789
|
|
|
|
|
|
|
{ |
790
|
|
|
|
|
|
|
# remap "horizontal_order: 5" to "rank: 5" |
791
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $value) = @_; |
792
|
|
|
|
|
|
|
|
793
|
0
|
|
|
|
|
0
|
my $rank = $value; |
794
|
|
|
|
|
|
|
# insert a really really high rank |
795
|
0
|
0
|
|
|
|
0
|
$rank = '1000000' if $value eq 'maxdepth'; |
796
|
|
|
|
|
|
|
|
797
|
|
|
|
|
|
|
# save the original value, too |
798
|
0
|
|
|
|
|
0
|
('x-vcg-horizontal_order', $value, 'rank', $rank); |
799
|
|
|
|
|
|
|
} |
800
|
|
|
|
|
|
|
|
801
|
|
|
|
|
|
|
sub _invisible_from_vcg |
802
|
|
|
|
|
|
|
{ |
803
|
|
|
|
|
|
|
# remap "invisible: yes" to "shape: invisible" |
804
|
1
|
|
|
1
|
|
2
|
my ($graph, $name, $value) = @_; |
805
|
|
|
|
|
|
|
|
806
|
1
|
50
|
|
|
|
3
|
return (undef,undef) if $value ne 'yes'; |
807
|
|
|
|
|
|
|
|
808
|
1
|
|
|
|
|
3
|
('shape', 'invisible'); |
809
|
|
|
|
|
|
|
} |
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
sub _manhattan_edges_from_vcg |
812
|
|
|
|
|
|
|
{ |
813
|
|
|
|
|
|
|
# remap "manhattan_edges: yes" for graphs |
814
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $value) = @_; |
815
|
|
|
|
|
|
|
|
816
|
0
|
0
|
|
|
|
0
|
if ($value eq 'yes') |
817
|
|
|
|
|
|
|
{ |
818
|
0
|
|
|
|
|
0
|
$graph->set_attribute('edge','start','front'); |
819
|
0
|
|
|
|
|
0
|
$graph->set_attribute('edge','end','back'); |
820
|
|
|
|
|
|
|
} |
821
|
|
|
|
|
|
|
# store the value for proper VCG output |
822
|
0
|
|
|
|
|
0
|
('x-vcg-' . $name, $value); |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
sub _textmode_from_vcg |
826
|
|
|
|
|
|
|
{ |
827
|
|
|
|
|
|
|
# remap "textmode: left_justify" to "align: left;" |
828
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $align) = @_; |
829
|
|
|
|
|
|
|
|
830
|
0
|
|
|
|
|
0
|
$align =~ s/_.*//; # left_justify => left |
831
|
|
|
|
|
|
|
|
832
|
0
|
|
|
|
|
0
|
('align', lc($align)); |
833
|
|
|
|
|
|
|
} |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub _edge_color_from_vcg |
836
|
|
|
|
|
|
|
{ |
837
|
|
|
|
|
|
|
# remap "darkyellow" to "rgb(128 128 0)" |
838
|
2
|
|
|
2
|
|
3
|
my ($graph, $name, $color) = @_; |
839
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
# print STDERR "edge $name $color\n"; |
841
|
|
|
|
|
|
|
# print STDERR ($vcg_edge_color_remap->{$name} || $name, " ", $vcg_color_by_name->{$color} || $color), "\n"; |
842
|
|
|
|
|
|
|
|
843
|
2
|
|
33
|
|
|
4
|
my $c = $vcg_color_by_name->{$color} || $color; |
844
|
2
|
50
|
33
|
|
|
6
|
$c = $graph->{_vcg_color_map}->[$c] if $c =~ /^[0-9]+\z/ && $c < 256; |
845
|
|
|
|
|
|
|
|
846
|
2
|
|
33
|
|
|
9
|
($vcg_edge_color_remap->{$name} || $name, $c); |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
sub _edge_class_from_vcg |
850
|
|
|
|
|
|
|
{ |
851
|
|
|
|
|
|
|
# remap "1" to "edgeclass1" to create a valid class name |
852
|
3
|
|
|
3
|
|
4
|
my ($graph, $name, $class) = @_; |
853
|
|
|
|
|
|
|
|
854
|
3
|
50
|
66
|
|
|
16
|
$class = $graph->{_vcg_class_names}->{$class} || ('edgeclass' . $class) if $class =~ /^[0-9]+\z/; |
855
|
|
|
|
|
|
|
#$class = 'edgeclass' . $class if $class !~ /^[a-zA-Z]/; |
856
|
|
|
|
|
|
|
|
857
|
3
|
|
|
|
|
8
|
('class', $class); |
858
|
|
|
|
|
|
|
} |
859
|
|
|
|
|
|
|
|
860
|
|
|
|
|
|
|
my $vcg_orientation = { |
861
|
|
|
|
|
|
|
top_to_bottom => 'south', |
862
|
|
|
|
|
|
|
bottom_to_top => 'north', |
863
|
|
|
|
|
|
|
left_to_right => 'east', |
864
|
|
|
|
|
|
|
right_to_left => 'west', |
865
|
|
|
|
|
|
|
}; |
866
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
sub _orientation_from_vcg |
868
|
|
|
|
|
|
|
{ |
869
|
4
|
|
|
4
|
|
8
|
my ($graph, $name, $value) = @_; |
870
|
|
|
|
|
|
|
|
871
|
4
|
|
50
|
|
|
18
|
('flow', $vcg_orientation->{$value} || 'south'); |
872
|
|
|
|
|
|
|
} |
873
|
|
|
|
|
|
|
|
874
|
|
|
|
|
|
|
sub _port_sharing_from_vcg |
875
|
|
|
|
|
|
|
{ |
876
|
|
|
|
|
|
|
# if we see this, add autojoin/autosplit |
877
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $value) = @_; |
878
|
|
|
|
|
|
|
|
879
|
0
|
0
|
|
|
|
0
|
$value = ($value =~ /yes/i) ? 'yes' : 'no'; |
880
|
|
|
|
|
|
|
|
881
|
0
|
|
|
|
|
0
|
('autojoin', $value, 'autosplit', $value); |
882
|
|
|
|
|
|
|
} |
883
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
sub _inport_sharing_from_vcg |
885
|
|
|
|
|
|
|
{ |
886
|
|
|
|
|
|
|
# if we see this, add autojoin/autosplit |
887
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $value) = @_; |
888
|
|
|
|
|
|
|
|
889
|
0
|
0
|
|
|
|
0
|
$value = ($value =~ /yes/i) ? 'yes' : 'no'; |
890
|
|
|
|
|
|
|
|
891
|
0
|
|
|
|
|
0
|
('autojoin', $value); |
892
|
|
|
|
|
|
|
} |
893
|
|
|
|
|
|
|
|
894
|
|
|
|
|
|
|
sub _outport_sharing_from_vcg |
895
|
|
|
|
|
|
|
{ |
896
|
|
|
|
|
|
|
# if we see this, add autojoin/autosplit |
897
|
0
|
|
|
0
|
|
0
|
my ($graph, $name, $value) = @_; |
898
|
|
|
|
|
|
|
|
899
|
0
|
0
|
|
|
|
0
|
$value = ($value =~ /yes/i) ? 'yes' : 'no'; |
900
|
|
|
|
|
|
|
|
901
|
0
|
|
|
|
|
0
|
('autosplit', $value); |
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
sub _node_color_from_vcg |
905
|
|
|
|
|
|
|
{ |
906
|
|
|
|
|
|
|
# remap "darkyellow" to "rgb(128 128 0)" |
907
|
7
|
|
|
7
|
|
9
|
my ($graph, $name, $color) = @_; |
908
|
|
|
|
|
|
|
|
909
|
7
|
|
66
|
|
|
18
|
my $c = $vcg_color_by_name->{$color} || $color; |
910
|
7
|
100
|
66
|
|
|
31
|
$c = $graph->{_vcg_color_map}->[$c] if $c =~ /^[0-9]+\z/ && $c < 256; |
911
|
|
|
|
|
|
|
|
912
|
7
|
|
33
|
|
|
22
|
($vcg_node_color_remap->{$name} || $name, $c); |
913
|
|
|
|
|
|
|
} |
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
my $shapes = { |
916
|
|
|
|
|
|
|
box => 'rect', |
917
|
|
|
|
|
|
|
rhomb => 'diamond', |
918
|
|
|
|
|
|
|
triangle => 'triangle', |
919
|
|
|
|
|
|
|
ellipse => 'ellipse', |
920
|
|
|
|
|
|
|
circle => 'circle', |
921
|
|
|
|
|
|
|
hexagon => 'hexagon', |
922
|
|
|
|
|
|
|
trapeze => 'trapezium', |
923
|
|
|
|
|
|
|
uptrapeze => 'invtrapezium', |
924
|
|
|
|
|
|
|
lparallelogram => 'invparallelogram', |
925
|
|
|
|
|
|
|
rparallelogram => 'parallelogram', |
926
|
|
|
|
|
|
|
}; |
927
|
|
|
|
|
|
|
|
928
|
|
|
|
|
|
|
sub _vcg_node_shape |
929
|
|
|
|
|
|
|
{ |
930
|
2
|
|
|
2
|
|
2
|
my ($self, $name, $shape) = @_; |
931
|
|
|
|
|
|
|
|
932
|
2
|
|
|
|
|
1
|
my @rc; |
933
|
2
|
|
|
|
|
3
|
my $s = lc($shape); |
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
# map the name to what Graph::Easy expects (ellipse stays as ellipse but |
936
|
|
|
|
|
|
|
# everything unknown gets converted to rect) |
937
|
2
|
|
50
|
|
|
5
|
$s = $shapes->{$s} || 'rect'; |
938
|
|
|
|
|
|
|
|
939
|
2
|
|
|
|
|
4
|
(@rc, $name, $s); |
940
|
|
|
|
|
|
|
} |
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
sub _group_name_from_vcg |
943
|
|
|
|
|
|
|
{ |
944
|
0
|
|
|
0
|
|
0
|
my ($self, $attr, $name, $object) = @_; |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
print STDERR "# Renaming anon group '$object->{name}' to '$name'\n" |
947
|
0
|
0
|
|
|
|
0
|
if $self->{debug} > 0; |
948
|
|
|
|
|
|
|
|
949
|
0
|
|
|
|
|
0
|
$self->rename_group($object, $name); |
950
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
# name was set, so drop the "title: name" pair |
952
|
0
|
|
|
|
|
0
|
(undef, undef); |
953
|
|
|
|
|
|
|
} |
954
|
|
|
|
|
|
|
|
955
|
|
|
|
|
|
|
############################################################################# |
956
|
|
|
|
|
|
|
|
957
|
|
|
|
|
|
|
sub _remap_attributes |
958
|
|
|
|
|
|
|
{ |
959
|
57
|
|
|
57
|
|
63
|
my ($self, $att, $object, $r) = @_; |
960
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
# print STDERR "# Remapping attributes\n"; |
962
|
|
|
|
|
|
|
# use Data::Dumper; print Dumper($att); |
963
|
|
|
|
|
|
|
|
964
|
|
|
|
|
|
|
# handle the "colorentry 00" entries: |
965
|
57
|
|
|
|
|
170
|
for my $key (sort keys %$att) |
966
|
|
|
|
|
|
|
{ |
967
|
87
|
100
|
|
|
|
112
|
if ($key =~ /^colorentry\s+([0-9]{1,2})/) |
968
|
|
|
|
|
|
|
{ |
969
|
|
|
|
|
|
|
# put the color into the current color map |
970
|
2
|
|
|
|
|
6
|
$self->_vcg_color_map_entry($1, $att->{$key}); |
971
|
2
|
|
|
|
|
3
|
delete $att->{$key}; |
972
|
2
|
|
|
|
|
3
|
next; |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
# remap \fi065 to 'A' |
976
|
85
|
|
|
|
|
98
|
$att->{$key} =~ s/(\x0c|\\f)i([0-9]{3})/ decode('iso-8859-1', chr($2)); /eg; |
|
2
|
|
|
|
|
10
|
|
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
# XXX TDOO: support inline colorations |
979
|
|
|
|
|
|
|
# remap \f65 to '' |
980
|
85
|
|
|
|
|
148
|
$att->{$key} =~ s/(\x0c|\\f)([0-9]{2})//g; |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
# remap \c09 to color 09: TODO for now remove |
983
|
85
|
|
|
|
|
78
|
$att->{$key} =~ s/(\x0c|\\f)([0-9]{2})//g; |
984
|
|
|
|
|
|
|
|
985
|
|
|
|
|
|
|
# XXX TODO: support real hor lines |
986
|
|
|
|
|
|
|
# insert a fake |
987
|
85
|
|
|
|
|
91
|
$att->{$key} =~ s/(\x0c|\\f)-/\\c ---- \\n /g; |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
} |
990
|
57
|
|
|
|
|
122
|
$self->SUPER::_remap_attributes($att,$object,$r); |
991
|
|
|
|
|
|
|
} |
992
|
|
|
|
|
|
|
|
993
|
|
|
|
|
|
|
############################################################################# |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
sub _parser_cleanup |
996
|
|
|
|
|
|
|
{ |
997
|
|
|
|
|
|
|
# After initial parsing, do cleanup. |
998
|
13
|
|
|
13
|
|
14
|
my ($self) = @_; |
999
|
|
|
|
|
|
|
|
1000
|
13
|
|
|
|
|
15
|
my $g = $self->{_graph}; |
1001
|
13
|
|
|
|
|
15
|
$g->{_warn_on_unknown_attributes} = 0; # reset to die again |
1002
|
|
|
|
|
|
|
|
1003
|
13
|
|
|
|
|
34
|
delete $g->{_vcg_color_map}; |
1004
|
13
|
|
|
|
|
17
|
delete $g->{_vcg_class_names}; |
1005
|
|
|
|
|
|
|
|
1006
|
13
|
|
|
|
|
16
|
$self; |
1007
|
|
|
|
|
|
|
} |
1008
|
|
|
|
|
|
|
|
1009
|
|
|
|
|
|
|
1; |
1010
|
|
|
|
|
|
|
__END__ |