| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package C::Scan; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
require Exporter; |
|
4
|
1
|
|
|
1
|
|
1010
|
use Config '%Config'; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
51
|
|
|
5
|
1
|
|
|
1
|
|
6
|
use File::Basename; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
133
|
|
|
6
|
1
|
|
|
1
|
|
1061
|
use Data::Flow qw(0.05); |
|
|
1
|
|
|
|
|
3330
|
|
|
|
1
|
|
|
|
|
131
|
|
|
7
|
1
|
|
|
1
|
|
6
|
use strict; # Earlier it catches ISA and EXPORT. |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
8264
|
|
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
@C::Scan::ISA = qw(Exporter Data::Flow); |
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
# Items to export into callers namespace by default. Note: do not export |
|
12
|
|
|
|
|
|
|
# names by default without a very good reason. Use EXPORT_OK instead. |
|
13
|
|
|
|
|
|
|
# Do not simply export all your public functions/methods/constants. |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
@C::Scan::EXPORT = qw( |
|
16
|
|
|
|
|
|
|
); |
|
17
|
|
|
|
|
|
|
@C::Scan::EXPORT_OK = qw( |
|
18
|
|
|
|
|
|
|
); |
|
19
|
|
|
|
|
|
|
# this flag tells cpp to only output macros |
|
20
|
|
|
|
|
|
|
$C::Scan::MACROS_ONLY = '-dM'; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
$C::Scan::VERSION = '0.74'; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
my (%keywords,%style_keywords); |
|
25
|
|
|
|
|
|
|
for (qw(asm auto break case char continue default do double else enum |
|
26
|
|
|
|
|
|
|
extern float for fortran goto if int long register return short |
|
27
|
|
|
|
|
|
|
sizeof static struct switch typedef union unsigned signed while void)) { |
|
28
|
|
|
|
|
|
|
$keywords{$_}++; |
|
29
|
|
|
|
|
|
|
} |
|
30
|
|
|
|
|
|
|
for (qw(bool class const delete friend inline new operator overload private |
|
31
|
|
|
|
|
|
|
protected public virtual)) { |
|
32
|
|
|
|
|
|
|
$style_keywords{'C++'}{$_}++; |
|
33
|
|
|
|
|
|
|
} |
|
34
|
|
|
|
|
|
|
for (qw(__func__ _Complex _Imaginary _Bool inline restrict)) { |
|
35
|
|
|
|
|
|
|
$style_keywords{'C9X'}{$_}++; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
|
|
|
|
|
|
for (qw(inline const asm noreturn format section |
|
38
|
|
|
|
|
|
|
constructor destructor unused weak)) { |
|
39
|
|
|
|
|
|
|
$style_keywords{'GNU'}{$_}++; |
|
40
|
|
|
|
|
|
|
$style_keywords{'GNU'}{"__$ {_}__"}++; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
$style_keywords{'GNU'}{__attribute__}++; |
|
43
|
|
|
|
|
|
|
$style_keywords{'GNU'}{__extension__}++; |
|
44
|
|
|
|
|
|
|
$style_keywords{'GNU'}{__consts}++; |
|
45
|
|
|
|
|
|
|
$style_keywords{'GNU'}{__const}++; |
|
46
|
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my $recipes |
|
48
|
|
|
|
|
|
|
= { Defines => { default => '' }, |
|
49
|
|
|
|
|
|
|
cppstdin => { default => $Config{cppstdin} }, |
|
50
|
|
|
|
|
|
|
cppflags => { default => $Config{cppflags} }, |
|
51
|
|
|
|
|
|
|
cppminus => { default => $Config{cppminus} }, |
|
52
|
|
|
|
|
|
|
c_styles => { default => [qw(C++ GNU C9X)] }, |
|
53
|
|
|
|
|
|
|
add_cppflags => { default => '' }, |
|
54
|
|
|
|
|
|
|
keywords => { prerequisites => ['c_styles'], |
|
55
|
|
|
|
|
|
|
output => sub { |
|
56
|
|
|
|
|
|
|
my %kw = %keywords; |
|
57
|
|
|
|
|
|
|
my %add; |
|
58
|
|
|
|
|
|
|
for ( @{ shift->{c_styles} } ) { |
|
59
|
|
|
|
|
|
|
%add = %{ $style_keywords{$_} }; |
|
60
|
|
|
|
|
|
|
%kw = (%kw, %add); |
|
61
|
|
|
|
|
|
|
} |
|
62
|
|
|
|
|
|
|
\%kw; |
|
63
|
|
|
|
|
|
|
}, }, |
|
64
|
|
|
|
|
|
|
'undef' => { default => undef }, |
|
65
|
|
|
|
|
|
|
filename_filter => { default => undef }, |
|
66
|
|
|
|
|
|
|
full_text => { class_filter => [ 'text', 'C::Preprocessed', |
|
67
|
|
|
|
|
|
|
qw(undef filename Defines includeDirs Cpp)] }, |
|
68
|
|
|
|
|
|
|
text => { class_filter => [ 'text', 'C::Preprocessed', |
|
69
|
|
|
|
|
|
|
qw(filename_filter filename Defines includeDirs Cpp)] }, |
|
70
|
|
|
|
|
|
|
text_only_from => { class_filter => [ 'text_only_from', 'C::Preprocessed', |
|
71
|
|
|
|
|
|
|
qw(filename_filter filename Defines includeDirs Cpp)] }, |
|
72
|
|
|
|
|
|
|
includes => { filter => [ \&includes, |
|
73
|
|
|
|
|
|
|
qw(filename Defines includeDirs Cpp) ], }, |
|
74
|
|
|
|
|
|
|
includeDirs => { prerequisites => ['filedir'], |
|
75
|
|
|
|
|
|
|
output => sub { |
|
76
|
|
|
|
|
|
|
my $data = shift; |
|
77
|
|
|
|
|
|
|
[ $data->{filedir}, '/usr/local/include', '.']; |
|
78
|
|
|
|
|
|
|
} }, |
|
79
|
|
|
|
|
|
|
Cpp => { prerequisites => [qw(cppminus add_cppflags cppflags cppstdin)], |
|
80
|
|
|
|
|
|
|
output => sub { |
|
81
|
|
|
|
|
|
|
my $data = shift; |
|
82
|
|
|
|
|
|
|
return { cppstdin => $data->{cppstdin}, |
|
83
|
|
|
|
|
|
|
cppflags => "$data->{cppflags} $data->{add_cppflags}", |
|
84
|
|
|
|
|
|
|
cppminus => $data->{cppminus} }; |
|
85
|
|
|
|
|
|
|
} }, |
|
86
|
|
|
|
|
|
|
filedir => { output => sub { dirname ( shift->{filename} || '.' ) } }, |
|
87
|
|
|
|
|
|
|
sanitized => { filter => [ \&sanitize, 'text'], }, |
|
88
|
|
|
|
|
|
|
toplevel => { filter => [ \&top_level, 'sanitized'], }, |
|
89
|
|
|
|
|
|
|
full_sanitized => { filter => [ \&sanitize, 'full_text'], }, |
|
90
|
|
|
|
|
|
|
full_toplevel => { filter => [ \&top_level, 'full_sanitized'], }, |
|
91
|
|
|
|
|
|
|
no_type_decl => { filter => [ \&remove_type_decl, 'toplevel'], }, |
|
92
|
|
|
|
|
|
|
typedef_chunks => { filter => [ \&typedef_chunks, 'full_toplevel'], }, |
|
93
|
|
|
|
|
|
|
typedefs_maybe => { filter => [ sub {[keys %{+shift}]}, 'typedef_hash'], }, |
|
94
|
|
|
|
|
|
|
typedefs_whited => { filter => [ \&typedefs_whited, |
|
95
|
|
|
|
|
|
|
'full_sanitized', 'typedef_chunks', |
|
96
|
|
|
|
|
|
|
'keywords_rex'], }, |
|
97
|
|
|
|
|
|
|
typedef_texts => { filter => [ \&typedef_texts, |
|
98
|
|
|
|
|
|
|
'full_text', 'typedef_chunks'], }, |
|
99
|
|
|
|
|
|
|
typedef_hash => { filter => [ \&typedef_hash, |
|
100
|
|
|
|
|
|
|
'typedef_texts', 'typedefs_whited'], }, |
|
101
|
|
|
|
|
|
|
typedef_structs => { filter => [ \&typedef_structs, |
|
102
|
|
|
|
|
|
|
'typedef_hash'], }, |
|
103
|
|
|
|
|
|
|
defines_maybe => { filter => [ \&defines_maybe, 'filename'], }, |
|
104
|
|
|
|
|
|
|
defines_no_args => { prerequisites => ['defines_maybe'], |
|
105
|
|
|
|
|
|
|
output => sub { shift->{defines_maybe}->[0] }, }, |
|
106
|
|
|
|
|
|
|
defines_args => { prerequisites => ['defines_maybe'], |
|
107
|
|
|
|
|
|
|
output => sub { shift->{defines_maybe}->[1] }, }, |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
defines_full => { filter => [ \&defines_full, |
|
110
|
|
|
|
|
|
|
qw(filename Defines includeDirs Cpp) ], }, |
|
111
|
|
|
|
|
|
|
defines_no_args_full => { prerequisites => ['defines_full'], |
|
112
|
|
|
|
|
|
|
output => sub { shift->{defines_full}->[0] }, }, |
|
113
|
|
|
|
|
|
|
defines_args_full => { prerequisites => ['defines_full'], |
|
114
|
|
|
|
|
|
|
output => sub { shift->{defines_full}->[1] }, }, |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
decl_inlines => { filter => [ \&functions_in, 'no_type_decl'], }, |
|
117
|
|
|
|
|
|
|
inline_chunks => { filter => [ sub { shift->[0] }, 'decl_inlines'], }, |
|
118
|
|
|
|
|
|
|
inlines => { filter => [ \&from_chunks, 'inline_chunks', 'text'], }, |
|
119
|
|
|
|
|
|
|
decl_chunks => { filter => [ sub { shift->[1] }, 'decl_inlines'], }, |
|
120
|
|
|
|
|
|
|
decls => { filter => [ \&from_chunks, 'decl_chunks', 'text'], }, |
|
121
|
|
|
|
|
|
|
fdecl_chunks => { filter => [ sub { shift->[4] }, 'decl_inlines'], }, |
|
122
|
|
|
|
|
|
|
fdecls => { filter => [ \&from_chunks, 'fdecl_chunks', 'text'], }, |
|
123
|
|
|
|
|
|
|
mdecl_chunks => { filter => [ sub { shift->[2] }, 'decl_inlines'], }, |
|
124
|
|
|
|
|
|
|
mdecls => { filter => [ \&from_chunks, 'mdecl_chunks', 'text'], }, |
|
125
|
|
|
|
|
|
|
vdecl_chunks => { filter => [ sub { shift->[3] }, 'decl_inlines'], }, |
|
126
|
|
|
|
|
|
|
vdecls => { filter => [ \&from_chunks, 'vdecl_chunks', 'text'], }, |
|
127
|
|
|
|
|
|
|
vdecl_hash => { filter => [ \&vdecl_hash, 'vdecls', 'mdecls' ], }, |
|
128
|
|
|
|
|
|
|
parsed_fdecls => { filter => [ \&do_declarations, 'fdecls', |
|
129
|
|
|
|
|
|
|
'typedef_hash', 'keywords'], }, |
|
130
|
|
|
|
|
|
|
keywords_rex => { filter => [ sub { my @k = keys %{ shift() }; |
|
131
|
|
|
|
|
|
|
local $" = '|'; |
|
132
|
|
|
|
|
|
|
my $r = "(?:@k)"; |
|
133
|
|
|
|
|
|
|
eval 'qr/$r/' or $r # Older Perls |
|
134
|
|
|
|
|
|
|
}, 'keywords'], }, |
|
135
|
|
|
|
|
|
|
}; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub from_chunks { |
|
138
|
4
|
|
|
4
|
0
|
136
|
my $chunks = shift; |
|
139
|
4
|
|
|
|
|
8
|
my $txt = shift; |
|
140
|
4
|
|
|
|
|
8
|
my @out; |
|
141
|
4
|
|
|
|
|
13
|
my $i = 0; |
|
142
|
4
|
|
|
|
|
28
|
while ($i < @$chunks) { |
|
143
|
1
|
|
|
|
|
6
|
push @out, substr $txt, $chunks->[$i], $chunks->[ $i + 1 ] - $chunks->[$i]; |
|
144
|
1
|
|
|
|
|
5
|
$i += 2; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
4
|
|
|
|
|
43
|
\@out; |
|
147
|
|
|
|
|
|
|
} |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
#sub process { request($recipes, @_) } |
|
150
|
|
|
|
|
|
|
# Preloaded methods go here. |
|
151
|
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub includes { |
|
153
|
2
|
|
|
2
|
0
|
29
|
my %seen; |
|
154
|
2
|
50
|
|
|
|
18
|
my $stream = new C::Preprocessed (@_) |
|
155
|
|
|
|
|
|
|
or die "Cannot open pipe from cppstdin: $!\n"; |
|
156
|
|
|
|
|
|
|
|
|
157
|
2
|
|
|
|
|
46067
|
while (<$stream>) { |
|
158
|
536
|
100
|
|
|
|
2548
|
next unless m(^\s*\#\s* # Leading hash |
|
159
|
|
|
|
|
|
|
(line\s*)? # 1: Optional line |
|
160
|
|
|
|
|
|
|
([0-9]+)\s* # 2: Line number |
|
161
|
|
|
|
|
|
|
(.*) # 3: The rest |
|
162
|
|
|
|
|
|
|
)x; |
|
163
|
110
|
|
|
|
|
310
|
my $include = $3; |
|
164
|
110
|
50
|
|
|
|
746
|
$include = $1 if $include =~ /"(.*)"/; # Filename may be in quotes |
|
165
|
110
|
50
|
|
|
|
715
|
$include =~ s,\\\\,/,g if $^O eq 'os2'; |
|
166
|
110
|
50
|
|
|
|
1817
|
$seen{$include}++ if $include ne ""; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
2
|
|
|
|
|
221
|
[keys %seen]; |
|
169
|
|
|
|
|
|
|
} |
|
170
|
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub defines_maybe { |
|
172
|
1
|
|
|
1
|
0
|
225
|
my $file = shift; |
|
173
|
1
|
|
|
|
|
5
|
my ($mline,$line,%macros,%macrosargs,$sym,$args); |
|
174
|
1
|
50
|
|
|
|
96
|
open(C, $file) or die "Cannot open file $file: $!\n"; |
|
175
|
1
|
|
66
|
|
|
49
|
while (not eof(C) and $line = ) { |
|
176
|
|
|
|
|
|
|
next unless |
|
177
|
730
|
50
|
|
|
|
2981
|
( $line =~ s[ |
|
178
|
|
|
|
|
|
|
^ \s* \# \s* # Start of directive |
|
179
|
|
|
|
|
|
|
define \s+ |
|
180
|
|
|
|
|
|
|
(\w+) # 1: symbol |
|
181
|
|
|
|
|
|
|
(?: |
|
182
|
|
|
|
|
|
|
\( (.*?) \s* \) # 2: Minimal match for arguments |
|
183
|
|
|
|
|
|
|
# in parenths (without trailing |
|
184
|
|
|
|
|
|
|
# spaces) |
|
185
|
|
|
|
|
|
|
)? # optional, no grouping |
|
186
|
|
|
|
|
|
|
\s* # rest is the definition |
|
187
|
|
|
|
|
|
|
([\s\S]*) # 3: the rest |
|
188
|
|
|
|
|
|
|
][]x ); |
|
189
|
0
|
|
|
|
|
0
|
($sym, $args, $mline) = ($1, $2, $3); |
|
190
|
0
|
|
0
|
|
|
0
|
$mline .= while not eof(C) and $mline =~ s/\\\n/\n/; |
|
191
|
0
|
|
|
|
|
0
|
chomp $mline; |
|
192
|
|
|
|
|
|
|
#print "sym: `$sym', args: `$args', mline: `$mline'\n"; |
|
193
|
0
|
0
|
|
|
|
0
|
if (defined $args) { |
|
194
|
0
|
|
|
|
|
0
|
$macrosargs{$sym} = [ [split /\s*,\s*/, $args], $mline]; |
|
195
|
|
|
|
|
|
|
} else { |
|
196
|
0
|
|
|
|
|
0
|
$macros{$sym} = $mline; |
|
197
|
|
|
|
|
|
|
} |
|
198
|
|
|
|
|
|
|
} |
|
199
|
1
|
50
|
|
|
|
23
|
close(C) or die "Cannot close file $file: $!\n"; |
|
200
|
1
|
|
|
|
|
16
|
[\%macros, \%macrosargs]; |
|
201
|
|
|
|
|
|
|
} |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
sub defines_full { |
|
204
|
1
|
|
|
1
|
0
|
17
|
my $Cpp = $_[3]; |
|
205
|
1
|
|
|
|
|
2
|
my ($mline,$line,%macros,%macrosargs,$sym,$args); |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
# save the old cppflags and add the flag for only ouputting macro definitions |
|
208
|
1
|
|
|
|
|
3
|
my $old_cppstdin = $Cpp->{'cppstdin'}; |
|
209
|
1
|
|
|
|
|
5
|
$Cpp->{'cppstdin'} = $old_cppstdin . " " . $C::Scan::MACROS_ONLY; |
|
210
|
|
|
|
|
|
|
|
|
211
|
1
|
50
|
|
|
|
8
|
my $stream = new C::Preprocessed (@_) |
|
212
|
|
|
|
|
|
|
or die "Cannot open pipe from cppstdin: $!\n"; |
|
213
|
|
|
|
|
|
|
|
|
214
|
1
|
|
|
|
|
22660
|
while (defined ($line = <$stream>)) { |
|
215
|
|
|
|
|
|
|
next unless |
|
216
|
239
|
50
|
|
|
|
1310
|
( $line =~ s[ |
|
217
|
|
|
|
|
|
|
^ \s* \# \s* # Start of directive |
|
218
|
|
|
|
|
|
|
define \s+ |
|
219
|
|
|
|
|
|
|
(\w+) # 1: symbol |
|
220
|
|
|
|
|
|
|
(?: |
|
221
|
|
|
|
|
|
|
\( (.*?) \s* \) # 2: Minimal match for arguments |
|
222
|
|
|
|
|
|
|
# in parenths (without trailing |
|
223
|
|
|
|
|
|
|
# spaces) |
|
224
|
|
|
|
|
|
|
)? # optional, no grouping |
|
225
|
|
|
|
|
|
|
\s* # rest is the definition |
|
226
|
|
|
|
|
|
|
([\s\S]*) # 3: the rest |
|
227
|
|
|
|
|
|
|
][]x ); |
|
228
|
239
|
|
|
|
|
3762
|
($sym, $args, $mline) = ($1, $2, $3); |
|
229
|
239
|
|
|
|
|
609
|
$mline .= <$stream> while ($mline =~ s/\\\n/\n/); |
|
230
|
239
|
|
|
|
|
264
|
chomp $mline; |
|
231
|
|
|
|
|
|
|
#print STDERR "sym: `$sym', args: `$args', mline: `$mline'\n"; |
|
232
|
239
|
100
|
|
|
|
354
|
if (defined $args) { |
|
233
|
10
|
|
|
|
|
233
|
$macrosargs{$sym} = [ [split /\s*,\s*/, $args], $mline]; |
|
234
|
|
|
|
|
|
|
} else { |
|
235
|
229
|
|
|
|
|
1229
|
$macros{$sym} = $mline; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
} |
|
238
|
|
|
|
|
|
|
# restore the original cppflags |
|
239
|
1
|
|
|
|
|
7
|
$Cpp->{'cppstdin'} = $old_cppstdin; |
|
240
|
1
|
|
|
|
|
32
|
[\%macros, \%macrosargs]; |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
|
|
243
|
|
|
|
|
|
|
# sub nexttypedef { |
|
244
|
|
|
|
|
|
|
# return unless $_[0] =~ /(\G|^|;)\s*typedef\b/g; |
|
245
|
|
|
|
|
|
|
# my $start = pos($_[0]) - 7; |
|
246
|
|
|
|
|
|
|
# nextsemi($_[0]); |
|
247
|
|
|
|
|
|
|
# my $end = pos $_[0]; |
|
248
|
|
|
|
|
|
|
# # warn "Found `", substr($_[0], $start, $end - $start), "'\n" if $debug; |
|
249
|
|
|
|
|
|
|
# return $start, $end; |
|
250
|
|
|
|
|
|
|
# } |
|
251
|
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
# sub nextsemi { |
|
253
|
|
|
|
|
|
|
# my $n = 0; |
|
254
|
|
|
|
|
|
|
# while ($_[0] =~ /([\(\{\[])|([\]\)\}])|(\;)/g) { |
|
255
|
|
|
|
|
|
|
# $n++ if defined $1; |
|
256
|
|
|
|
|
|
|
# $n-- if defined $2; |
|
257
|
|
|
|
|
|
|
# return if defined $3 and $n == 0; |
|
258
|
|
|
|
|
|
|
# } |
|
259
|
|
|
|
|
|
|
# die "No semicolon on the outer level"; |
|
260
|
|
|
|
|
|
|
# } |
|
261
|
|
|
|
|
|
|
|
|
262
|
|
|
|
|
|
|
sub typedef_texts { |
|
263
|
1
|
|
|
1
|
0
|
38
|
my ($txt, $chunks) = (shift, shift); |
|
264
|
1
|
|
|
|
|
7
|
my ($b, $e, $in, @out); |
|
265
|
1
|
|
|
|
|
34
|
my @in = @$chunks; |
|
266
|
1
|
|
|
|
|
15
|
while (($b, $e) = splice @in, 0, 2) { |
|
267
|
81
|
|
|
|
|
171
|
$in = substr($txt, $b, $e - $b); |
|
268
|
|
|
|
|
|
|
# remove any remaining directives |
|
269
|
81
|
|
|
|
|
274
|
$in =~ s/^ ( \s* \# .* ( \\ $ \n .* )* ) / ' ' x length($1)/xgem; |
|
|
0
|
|
|
|
|
0
|
|
|
270
|
81
|
|
|
|
|
309
|
push @out, $in; |
|
271
|
|
|
|
|
|
|
} |
|
272
|
1
|
|
|
|
|
17
|
\@out; |
|
273
|
|
|
|
|
|
|
} |
|
274
|
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
sub typedef_hash_old { |
|
276
|
0
|
|
|
0
|
0
|
0
|
+{ map {($_,1)} map /(\w+)/, @{$_[0]} }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
277
|
|
|
|
|
|
|
} |
|
278
|
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
sub typedef_hash { |
|
280
|
1
|
|
|
1
|
0
|
14
|
my ($typedefs, $whited) = (shift,shift); |
|
281
|
1
|
|
|
|
|
2
|
my %out; |
|
282
|
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
loop: |
|
284
|
1
|
|
|
|
|
5
|
for my $o (0..$#$typedefs) { |
|
285
|
81
|
|
|
|
|
96
|
my $wh = $whited->[$o]; |
|
286
|
81
|
|
|
|
|
78
|
my $td = $typedefs->[$o]; |
|
287
|
81
|
50
|
33
|
|
|
380
|
if ($wh =~ /,/ or not $wh =~ /\w/) { # Hard case, guessimates ... |
|
288
|
|
|
|
|
|
|
# Determine whether the new thingies are inside parens |
|
289
|
0
|
|
|
|
|
0
|
$wh =~ /,/g; |
|
290
|
0
|
|
|
|
|
0
|
my $p = pos $wh; |
|
291
|
0
|
|
|
|
|
0
|
my ($s, $e); |
|
292
|
0
|
0
|
|
|
|
0
|
if (matchingbrace($wh)) { # Inside. Easy part: just split on /,/... |
|
293
|
0
|
|
|
|
|
0
|
$e = pos($wh) - 1; |
|
294
|
0
|
|
|
|
|
0
|
$s = $e; |
|
295
|
0
|
|
|
|
|
0
|
my $d = 0; |
|
296
|
|
|
|
|
|
|
# Skip back |
|
297
|
0
|
|
|
|
|
0
|
while (--$s >= 0) { |
|
298
|
0
|
|
|
|
|
0
|
my $c = substr $wh, $s, 1; |
|
299
|
0
|
0
|
|
|
|
0
|
if ($c =~ /[\(\{\[]/) { |
|
|
|
0
|
|
|
|
|
|
|
300
|
0
|
|
|
|
|
0
|
$d--; |
|
301
|
|
|
|
|
|
|
} elsif ($c =~ /[\)\]\}]/) { |
|
302
|
0
|
|
|
|
|
0
|
$d++; |
|
303
|
|
|
|
|
|
|
} |
|
304
|
0
|
0
|
|
|
|
0
|
last if $d < 0; |
|
305
|
|
|
|
|
|
|
} |
|
306
|
0
|
0
|
|
|
|
0
|
if ($s < 0) { # Should not happen |
|
307
|
0
|
|
|
|
|
0
|
warn("panic: could not match braces in\n\t$td\nwhited as\n\t$wh\n"); |
|
308
|
0
|
|
|
|
|
0
|
next loop; |
|
309
|
|
|
|
|
|
|
} |
|
310
|
0
|
|
|
|
|
0
|
$s++; |
|
311
|
|
|
|
|
|
|
} else { # We are at toplevel |
|
312
|
|
|
|
|
|
|
# We need to skip back all the modifiers attached to the first thingy |
|
313
|
|
|
|
|
|
|
# Guesstimates: everything after the first '*' (inclusive) |
|
314
|
0
|
|
|
|
|
0
|
pos $wh = 0; |
|
315
|
0
|
|
|
|
|
0
|
$wh = /(?=\w)/g; |
|
316
|
0
|
|
|
|
|
0
|
my $ws = pos $wh; |
|
317
|
0
|
|
|
|
|
0
|
my $pre = substr $wh, 0, $ws; |
|
318
|
0
|
|
|
|
|
0
|
$s = $ws; |
|
319
|
0
|
0
|
|
|
|
0
|
$s = pos $pre if $pre =~ /(?=\*)/g; |
|
320
|
0
|
|
|
|
|
0
|
$e = length $wh; |
|
321
|
|
|
|
|
|
|
} |
|
322
|
|
|
|
|
|
|
# Now: need to split $td based on commas in $wh! |
|
323
|
|
|
|
|
|
|
# And need to split each chunk of $td based on word in the chunk of $wh! |
|
324
|
0
|
|
|
|
|
0
|
my $td_decls = substr($td, $s, $e - $s); |
|
325
|
0
|
|
|
|
|
0
|
my ($pre, $post) = (substr($td, 0, $s), substr($td, $e)); |
|
326
|
0
|
|
|
|
|
0
|
my $wh_decls = substr($wh, $s, $e - $s); |
|
327
|
0
|
|
|
|
|
0
|
my @wh_decls = split /,/, $wh_decls; |
|
328
|
0
|
|
|
|
|
0
|
my $td_s = 0; |
|
329
|
0
|
|
|
|
|
0
|
my (@td_decl, @td_pre, @td_post, @td_word); |
|
330
|
0
|
|
|
|
|
0
|
for my $wh_d (@wh_decls) { |
|
331
|
0
|
|
|
|
|
0
|
my $td_d = substr $td, $td_s, length $wh_d; |
|
332
|
0
|
|
|
|
|
0
|
push @td_decl, $td_d; |
|
333
|
0
|
|
|
|
|
0
|
$wh_d =~ /(\w+)/g; |
|
334
|
0
|
|
|
|
|
0
|
push @td_word, $1; |
|
335
|
0
|
|
|
|
|
0
|
push @td_post, substr $td_d, pos($wh_d); |
|
336
|
0
|
|
|
|
|
0
|
push @td_pre, substr $td_d, pos($wh_d) - length $1, length $1; |
|
337
|
0
|
|
|
|
|
0
|
$td_s += 1 + length $wh_d; # Skip over ',' |
|
338
|
|
|
|
|
|
|
} |
|
339
|
0
|
|
|
|
|
0
|
for my $i (0..$#wh_decls) { |
|
340
|
0
|
|
|
|
|
0
|
my $p = "$td_post[$i]$post"; |
|
341
|
0
|
0
|
|
|
|
0
|
$p = '' unless $p =~ /\S/; |
|
342
|
0
|
|
|
|
|
0
|
$out{$td_word[$i]} = ["$pre$td_pre[$i]", $p]; |
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
} else { # Only one thing defined... |
|
345
|
81
|
|
|
|
|
169
|
$wh =~ /(\w+)/g; |
|
346
|
81
|
|
|
|
|
86
|
my $e = pos $wh; |
|
347
|
81
|
|
|
|
|
106
|
my $s = $e - length $1; |
|
348
|
81
|
|
|
|
|
93
|
my $type = $1; |
|
349
|
81
|
|
|
|
|
96
|
my $pre = substr $td, 0, $s; |
|
350
|
81
|
|
|
|
|
134
|
my $post = substr $td, $e, length($td) - $e; |
|
351
|
81
|
100
|
|
|
|
172
|
$post = '' unless $post =~ /\S/; |
|
352
|
81
|
|
|
|
|
296
|
$out{$type} = [$pre, $post]; |
|
353
|
|
|
|
|
|
|
} |
|
354
|
|
|
|
|
|
|
} |
|
355
|
1
|
|
|
|
|
6
|
\%out; |
|
356
|
|
|
|
|
|
|
} |
|
357
|
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub typedef_chunks { # Input is toplevel, output: starts and ends |
|
359
|
1
|
|
|
1
|
0
|
16
|
my $txt = shift; |
|
360
|
1
|
|
|
|
|
17
|
pos $txt = 0; |
|
361
|
1
|
|
|
|
|
4
|
my ($b, $e, @out); |
|
362
|
1
|
|
|
|
|
26
|
while ($txt =~ /\btypedef\b/g) { |
|
363
|
81
|
|
|
|
|
291
|
push @out, pos $txt; |
|
364
|
81
|
|
|
|
|
568
|
$txt =~ /(?=;)|\Z/g; |
|
365
|
81
|
|
|
|
|
557
|
push @out, pos $txt; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
1
|
|
|
|
|
18
|
\@out; |
|
368
|
|
|
|
|
|
|
} |
|
369
|
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
sub typedef_structs { |
|
371
|
1
|
|
|
1
|
0
|
397
|
my $typehash = shift; |
|
372
|
1
|
|
|
|
|
3
|
my %structs; |
|
373
|
1
|
|
|
|
|
20
|
while (my($key, $text) = each %$typehash) { |
|
374
|
81
|
|
|
|
|
245
|
my $name = parse_struct($text->[0], \%structs); |
|
375
|
81
|
100
|
|
|
|
648
|
$structs{$key} = defined($name) ? $structs{$name} : undef; |
|
376
|
|
|
|
|
|
|
} |
|
377
|
1
|
|
|
|
|
14
|
\%structs; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
|
|
|
|
|
|
|
|
380
|
|
|
|
|
|
|
sub parse_struct { |
|
381
|
81
|
|
|
81
|
0
|
592
|
my($in, $structs) = @_; |
|
382
|
81
|
|
|
|
|
121
|
my($b, $e, $chunk, $vars, $struct, $structname); |
|
383
|
81
|
100
|
|
|
|
608
|
($structname, $in) = $in =~ / |
|
384
|
|
|
|
|
|
|
^ \s* ( (?: struct | union ) (?: \s+ \w+ )? ) \s* { \s* (.*?) \s* } \s* $ |
|
385
|
|
|
|
|
|
|
/gisx or return; |
|
386
|
3
|
50
|
|
|
|
21
|
$structname .= " _ANON" unless $structname =~ /\s/; |
|
387
|
3
|
100
|
|
|
|
13
|
$structname .= " 0" if exists $structs->{$structname}; |
|
388
|
3
|
|
|
|
|
22
|
$structname =~ s/(\d+$)/$1 + 1/e while exists $structs->{$structname}; |
|
|
1
|
|
|
|
|
12
|
|
|
389
|
3
|
|
|
|
|
6
|
$b = 0; |
|
390
|
3
|
|
|
|
|
49
|
while ($in =~ /(\{|;|$)/g) { |
|
391
|
6
|
50
|
|
|
|
25
|
matchingbrace($in), next if $1 eq '{'; |
|
392
|
6
|
|
|
|
|
11
|
$e = pos($in); |
|
393
|
6
|
100
|
|
|
|
26
|
next if $b == $e; |
|
394
|
3
|
|
|
|
|
13
|
$chunk = substr($in, $b, $e - $b); |
|
395
|
3
|
|
|
|
|
5
|
$b = $e; |
|
396
|
3
|
50
|
|
|
|
17
|
if ($chunk =~ /\G\s*(struct|union).*\}/gs) { |
|
397
|
0
|
|
|
|
|
0
|
my $term = pos $chunk; |
|
398
|
0
|
|
|
|
|
0
|
my $name = parse_struct(substr($chunk, 0, $term), $structs); |
|
399
|
0
|
|
|
|
|
0
|
$vars = parse_vars(join ' ', $name, substr $chunk, $term); |
|
400
|
|
|
|
|
|
|
} else { |
|
401
|
3
|
|
|
|
|
12
|
$vars = parse_vars($chunk); |
|
402
|
|
|
|
|
|
|
} |
|
403
|
3
|
|
|
|
|
18
|
push @$struct, @$vars; |
|
404
|
|
|
|
|
|
|
} |
|
405
|
3
|
|
|
|
|
10
|
$structs->{$structname} = $struct; |
|
406
|
3
|
|
|
|
|
13
|
$structname; |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub parse_vars { |
|
410
|
3
|
|
|
3
|
0
|
6
|
my $in = shift; |
|
411
|
3
|
|
|
|
|
7
|
my($vars, $type, $word, $id, $post); |
|
412
|
3
|
|
|
|
|
27
|
while ($in =~ /\G\s*([\[;,]|\S+?\b|$)\s*/g) { |
|
413
|
17
|
|
|
|
|
40
|
$word = $1; |
|
414
|
17
|
100
|
100
|
|
|
131
|
if ($word eq ';' || $word eq '') { |
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
415
|
6
|
100
|
|
|
|
30
|
next unless defined $id; |
|
416
|
3
|
50
|
|
|
|
8
|
$type = 'int' unless defined $type; # or is this an error? |
|
417
|
3
|
|
|
|
|
24
|
push @$vars, [ $type, $post, $id ]; |
|
418
|
3
|
|
|
|
|
20
|
($type, $post, $id) = (undef, undef, undef); |
|
419
|
|
|
|
|
|
|
} elsif ($word eq ',') { |
|
420
|
0
|
0
|
|
|
|
0
|
warn "panic: expecting name before comma in '$in'\n" unless defined $id; |
|
421
|
0
|
0
|
|
|
|
0
|
$type = 'int' unless defined $type; # or is this an error? |
|
422
|
0
|
|
|
|
|
0
|
push @$vars, [ $type, $post, $id ]; |
|
423
|
0
|
|
|
|
|
0
|
$type =~ s/[ *]*$//; |
|
424
|
0
|
|
|
|
|
0
|
$id = undef; |
|
425
|
|
|
|
|
|
|
} elsif ($word eq '[') { |
|
426
|
3
|
50
|
|
|
|
11
|
warn "panic: expecting name before '[' in '$in'\n" unless defined $id; |
|
427
|
3
|
50
|
|
|
|
9
|
$type = 'int' unless defined $type; # or is this an error? |
|
428
|
3
|
|
|
|
|
7
|
my $b = pos $in; |
|
429
|
3
|
|
|
|
|
10
|
matchingbrace($in); |
|
430
|
3
|
|
|
|
|
361
|
$post .= $word . substr $in, $b, pos($in) - $b; |
|
431
|
|
|
|
|
|
|
} else { |
|
432
|
8
|
50
|
|
|
|
20
|
if (defined $post) { |
|
433
|
0
|
|
|
|
|
0
|
warn "panic: not expecting '$word' after array bounds in '$in'\n"; |
|
434
|
|
|
|
|
|
|
} else { |
|
435
|
8
|
100
|
|
|
|
197
|
$type = join ' ', grep defined, $type, $id if defined $id; |
|
436
|
8
|
|
|
|
|
148
|
$id = $word; |
|
437
|
|
|
|
|
|
|
} |
|
438
|
|
|
|
|
|
|
} |
|
439
|
|
|
|
|
|
|
} |
|
440
|
3
|
|
|
|
|
12
|
$vars; |
|
441
|
|
|
|
|
|
|
} |
|
442
|
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
sub vdecl_hash { |
|
444
|
1
|
|
|
1
|
0
|
238
|
my($vdecls, $mdecls) = @_; |
|
445
|
1
|
|
|
|
|
3
|
my %vdecl_hash; |
|
446
|
1
|
|
|
|
|
5
|
for (@$vdecls, @$mdecls) { |
|
447
|
0
|
0
|
|
|
|
0
|
next if /[()]/; # ignore functions, and function pointers |
|
448
|
0
|
|
|
|
|
0
|
my $copy = $_; |
|
449
|
0
|
0
|
|
|
|
0
|
next unless $copy =~ s/^\s*extern\s*//; |
|
450
|
0
|
|
|
|
|
0
|
my $vars = parse_vars($copy); |
|
451
|
0
|
|
|
|
|
0
|
$vdecl_hash{$_->[2]} = [ @$_[0, 1] ] for @$vars; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
1
|
|
|
|
|
13
|
\%vdecl_hash; |
|
454
|
|
|
|
|
|
|
} |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
# The output is the list of list of inline chunks and list of |
|
457
|
|
|
|
|
|
|
# declaration chunks. |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
sub functions_in { # The arg is text without type declarations. |
|
460
|
1
|
|
|
1
|
0
|
38
|
my $in = shift; # remove_type_decl(top_level(sanitize($txt))); |
|
461
|
|
|
|
|
|
|
# What remains now consists of variable and function declarations, |
|
462
|
|
|
|
|
|
|
# and inline functions. |
|
463
|
1
|
|
|
|
|
47
|
$in =~ /(?=\S)/g; |
|
464
|
1
|
|
|
|
|
8
|
my ($b, $e, $b1, $e1, @inlines, @decls, @mdecls, @fdecls, @vdecls); |
|
465
|
1
|
|
|
|
|
7
|
$b = pos $in; |
|
466
|
1
|
|
|
|
|
2
|
my $chunk; |
|
467
|
1
|
|
|
|
|
25
|
while ($b != length $in) { |
|
468
|
1
|
50
|
|
|
|
15
|
$in =~ /;/g or pos $in = $b, $in =~ /.*\S|\Z/g ; # Or last non-space |
|
469
|
1
|
|
|
|
|
4
|
$e = pos $in; |
|
470
|
1
|
|
|
|
|
6
|
$chunk = substr $in, $b, $e - $b; |
|
471
|
|
|
|
|
|
|
# Now subdivide the chunk. |
|
472
|
|
|
|
|
|
|
# |
|
473
|
|
|
|
|
|
|
# What we got is one chunk, probably finished by `;'. Whoever, it |
|
474
|
|
|
|
|
|
|
# may start with several inline functions. |
|
475
|
|
|
|
|
|
|
# |
|
476
|
|
|
|
|
|
|
# Note that inline functions contain ( ) { } in the stripped version. |
|
477
|
1
|
|
|
|
|
3
|
$b1 = 0; |
|
478
|
1
|
|
|
|
|
34
|
while ($chunk =~ /\(\s*\)\s*\{\s*\}/g) { |
|
479
|
0
|
|
|
|
|
0
|
$e1 = pos $chunk; |
|
480
|
0
|
|
|
|
|
0
|
push @inlines, $b + $b1, $b + $e1; |
|
481
|
0
|
|
|
|
|
0
|
$chunk =~ /(?=\S)/g; |
|
482
|
0
|
|
|
|
|
0
|
$b1 = pos $chunk; |
|
483
|
0
|
0
|
|
|
|
0
|
$b1 = length $chunk, last unless defined $b1; |
|
484
|
|
|
|
|
|
|
} |
|
485
|
1
|
50
|
|
|
|
10
|
if ($e - $b - $b1 > 0) { |
|
486
|
1
|
|
|
|
|
8
|
push @decls, $b + $b1, $e; |
|
487
|
1
|
|
|
|
|
12
|
substr ($chunk, 0, $b1) = ''; |
|
488
|
1
|
50
|
|
|
|
9
|
if ($chunk =~ /,/) { # Contains multiple declarations. |
|
489
|
0
|
|
|
|
|
0
|
push @mdecls, $b + $b1, $e; |
|
490
|
|
|
|
|
|
|
} else { # Non-multiple. |
|
491
|
1
|
|
|
|
|
4
|
my $isvar = 1; |
|
492
|
|
|
|
|
|
|
# Since leading \s* is not optimized, this is quadratic! |
|
493
|
1
|
|
|
|
|
92
|
$chunk =~ s{ |
|
494
|
|
|
|
|
|
|
( ( const |
|
495
|
|
|
|
|
|
|
| __attribute__ \s* \( \s* \) |
|
496
|
|
|
|
|
|
|
) \s* )* ( ; \s* )? \Z # Strip from the end |
|
497
|
|
|
|
|
|
|
}()x; |
|
498
|
1
|
|
|
|
|
52
|
$chunk =~ s/\s*\Z//; |
|
499
|
1
|
50
|
|
|
|
12
|
if ($chunk =~ /\)\Z/) { # Function declaration ends on ")"! |
|
500
|
1
|
50
|
33
|
|
|
24
|
if ($chunk !~ m{ |
|
501
|
|
|
|
|
|
|
\( .* \( # Multiple parenths |
|
502
|
|
|
|
|
|
|
}x |
|
503
|
|
|
|
|
|
|
and $chunk =~ / \w \s* \( /x) { # Most probably pointer to a function? |
|
504
|
1
|
|
|
|
|
3
|
$isvar = 0; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
} |
|
507
|
1
|
50
|
|
|
|
16
|
if ($isvar) { # Heuristically variable |
|
508
|
0
|
|
|
|
|
0
|
push @vdecls, $b + $b1, $e; |
|
509
|
|
|
|
|
|
|
} else { |
|
510
|
1
|
|
|
|
|
5
|
push @fdecls, $b + $b1, $e; |
|
511
|
|
|
|
|
|
|
} |
|
512
|
|
|
|
|
|
|
} |
|
513
|
|
|
|
|
|
|
} |
|
514
|
1
|
|
|
|
|
9
|
$in =~ /\G\s*/g ; |
|
515
|
1
|
|
|
|
|
6
|
$b = pos $in; |
|
516
|
|
|
|
|
|
|
} |
|
517
|
1
|
|
|
|
|
13
|
[\@inlines, \@decls, \@mdecls, \@vdecls, \@fdecls]; |
|
518
|
|
|
|
|
|
|
} |
|
519
|
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
sub typedefs_whited { # Input is sanitized text, and list of beg/end. |
|
521
|
1
|
|
|
1
|
0
|
20
|
my @lst = @{$_[1]}; |
|
|
1
|
|
|
|
|
20
|
|
|
522
|
1
|
|
|
|
|
3
|
my @out; |
|
523
|
1
|
|
|
|
|
2
|
my ($b, $e); |
|
524
|
1
|
|
|
|
|
6
|
while ($b = shift @lst) { |
|
525
|
81
|
|
|
|
|
154
|
$e = shift @lst; |
|
526
|
81
|
|
|
|
|
272
|
push @out, whited_decl($_[2], substr $_[0], $b, $e - $b); |
|
527
|
|
|
|
|
|
|
} |
|
528
|
1
|
|
|
|
|
8
|
\@out; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
# XXXX This is heuristical in many respects... |
|
532
|
|
|
|
|
|
|
# Recipe: remove all struct-ish chunks. Remove all array specifiers. |
|
533
|
|
|
|
|
|
|
# Remove GCC attribute specifiers. |
|
534
|
|
|
|
|
|
|
# What remains may contain function's arguments, old types, and newly |
|
535
|
|
|
|
|
|
|
# defined types. |
|
536
|
|
|
|
|
|
|
# Remove function arguments using heuristics methods. |
|
537
|
|
|
|
|
|
|
# Now out of several words in a row the last one is a newly defined type. |
|
538
|
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
sub whited_decl { # Input is sanitized. |
|
540
|
81
|
|
|
81
|
0
|
127
|
my $keywords_rex = shift; |
|
541
|
81
|
|
|
|
|
169
|
my $in = shift; # Text of a declaration |
|
542
|
81
|
|
|
|
|
110
|
my $rest = $in; |
|
543
|
81
|
|
|
|
|
101
|
my $out = $in; # Whited out $in |
|
544
|
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
# Remove all the structs |
|
546
|
81
|
|
|
|
|
257
|
while ($out =~ /(\b(struct|union|class|enum)(\s+\w+)?\s*\{)/g) { |
|
547
|
3
|
|
|
|
|
8
|
my $pos_start = pos($out) - length $1; |
|
548
|
|
|
|
|
|
|
|
|
549
|
3
|
|
|
|
|
7
|
matchingbrace($out); |
|
550
|
3
|
|
|
|
|
5
|
my $pos_end = pos $out; |
|
551
|
3
|
|
|
|
|
14
|
substr($out, $pos_start, $pos_end - $pos_start) = |
|
552
|
|
|
|
|
|
|
' ' x ($pos_end - $pos_start); |
|
553
|
3
|
|
|
|
|
16
|
pos $out = $pos_end; |
|
554
|
|
|
|
|
|
|
} |
|
555
|
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
# Deal with glibc's wierd ass __attribute__ tag. Just dump it. |
|
557
|
|
|
|
|
|
|
# Maaaybe this should check to see if you're using GCC, but I don't |
|
558
|
|
|
|
|
|
|
# think so since glibc is nice enough to do that for you. [MGS] |
|
559
|
81
|
|
|
|
|
235
|
while ( $out =~ m/(\b(__attribute__|attribute)\s*\((?=\s*\())/g ) { |
|
560
|
9
|
|
|
|
|
21
|
my $att_pos_start = pos($out) - length($1); |
|
561
|
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
# Need to figure out where ((..)) ends. |
|
563
|
9
|
|
|
|
|
18
|
matchingbrace($out); |
|
564
|
9
|
|
|
|
|
11
|
my $att_pos_end = pos $out; |
|
565
|
|
|
|
|
|
|
|
|
566
|
|
|
|
|
|
|
# Remove the __attribute__ tag. |
|
567
|
9
|
|
|
|
|
25
|
substr($out, $att_pos_start, $att_pos_end - $att_pos_start) = |
|
568
|
|
|
|
|
|
|
' ' x ($att_pos_end - $att_pos_start); |
|
569
|
9
|
|
|
|
|
34
|
pos $out = $att_pos_end; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
# Remove arguments of functions (heuristics only). |
|
573
|
|
|
|
|
|
|
# These things (start) arglist of a declared function: |
|
574
|
|
|
|
|
|
|
# paren word comma |
|
575
|
|
|
|
|
|
|
# paren word space non-paren |
|
576
|
|
|
|
|
|
|
# paren keyword paren |
|
577
|
|
|
|
|
|
|
# start a list of arguments. (May be "cdecl *myfunc"?) XXXXX ????? |
|
578
|
81
|
|
|
|
|
822
|
while ( $out =~ /(\(\s*(\w+(,|\s+[^\)\s])|$keywords_rex\s*\)))/g ) { |
|
579
|
0
|
|
|
|
|
0
|
my $pos_start = pos($out) - length($1); |
|
580
|
0
|
|
|
|
|
0
|
pos $out = $pos_start + 1; |
|
581
|
0
|
|
|
|
|
0
|
matchingbrace($out); |
|
582
|
0
|
|
|
|
|
0
|
substr ($out, $pos_start + 1, pos($out) - 2 - $pos_start) |
|
583
|
|
|
|
|
|
|
= ' ' x (pos($out) - 2 - $pos_start); |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
# Remove array specifiers |
|
586
|
81
|
|
|
|
|
148
|
$out =~ s/(\[[\w\s\+]*\])/ ' ' x length $1 /ge; |
|
|
0
|
|
|
|
|
0
|
|
|
587
|
81
|
|
|
|
|
123
|
my $tout = $out; |
|
588
|
|
|
|
|
|
|
# Several words in a row cannot be new typedefs, but the last one. |
|
589
|
81
|
|
|
|
|
548
|
$out =~ s/((\w+\s+)+(?=[^\s,;\[\{\)]))/ ' ' x length $1 /ge; |
|
|
78
|
|
|
|
|
574
|
|
|
590
|
81
|
50
|
|
|
|
307
|
unless ($out =~ /\w/) { |
|
591
|
|
|
|
|
|
|
# Probably a function-type declaration: typedef int f(int); |
|
592
|
|
|
|
|
|
|
# Redo scan leaving the last word of the first group of words: |
|
593
|
0
|
|
|
|
|
0
|
$tout =~ /(\w+\s+)*(\w+)/g; |
|
594
|
0
|
|
|
|
|
0
|
$out = ' ' x (pos($tout) - length $2) |
|
595
|
|
|
|
|
|
|
. $2 . ' ' x (length($tout) - pos($tout)); |
|
596
|
|
|
|
|
|
|
# warn "function typedef\n\t'$in'\nwhited-out as\n\t'$out'\n"; |
|
597
|
|
|
|
|
|
|
} |
|
598
|
81
|
50
|
|
|
|
198
|
warn "panic: length mismatch\n\t'$in'\nwhited-out as\n\t'$out'\n" |
|
599
|
|
|
|
|
|
|
if length($in) != length $out; |
|
600
|
|
|
|
|
|
|
# Sanity check |
|
601
|
81
|
50
|
|
|
|
307
|
warn "panic: multiple types without intervening comma in\n\t$in\nwhited-out as\n\t$out\n" |
|
602
|
|
|
|
|
|
|
if $out =~ /\w[^\w,]+\w/; |
|
603
|
81
|
50
|
|
|
|
264
|
warn "panic: no types found in\n\t$in\nwhited-out as\n\t$out\n" |
|
604
|
|
|
|
|
|
|
unless $out =~ /\w/; |
|
605
|
81
|
|
|
|
|
400
|
$out |
|
606
|
|
|
|
|
|
|
} |
|
607
|
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
sub matchingbrace { |
|
609
|
|
|
|
|
|
|
# pos($_[0]) is after the opening brace now |
|
610
|
44
|
|
|
44
|
0
|
74
|
my $n = 0; |
|
611
|
44
|
|
|
|
|
517
|
while ($_[0] =~ /([\{\[\(])|([\]\)\}])/g) { |
|
612
|
210
|
100
|
|
|
|
490
|
$1 ? $n++ : $n-- ; |
|
613
|
210
|
100
|
|
|
|
1907
|
return 1 if $n < 0; |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
# pos($_[0]) is after the closing brace now |
|
616
|
0
|
|
|
|
|
0
|
return; # false |
|
617
|
|
|
|
|
|
|
} |
|
618
|
|
|
|
|
|
|
|
|
619
|
|
|
|
|
|
|
sub remove_Comments_no_Strings { # We expect that no strings are around |
|
620
|
0
|
|
|
0
|
0
|
0
|
my $in = shift; |
|
621
|
0
|
|
|
|
|
0
|
$in =~ s,/(/.*|\*[\s\S]*?\*/),,g ; # C and C++ |
|
622
|
0
|
0
|
|
|
|
0
|
die "Unfinished comment" if $in =~ m,/\*, ; |
|
623
|
0
|
|
|
|
|
0
|
$in; |
|
624
|
|
|
|
|
|
|
} |
|
625
|
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
sub sanitize { # We expect that no strings are around |
|
627
|
2
|
|
|
2
|
0
|
286
|
my $in = shift; |
|
628
|
|
|
|
|
|
|
# C and C++, strings and characters |
|
629
|
2
|
|
|
|
|
68
|
$in =~ s{ / ( |
|
630
|
|
|
|
|
|
|
/ .* # C++ style |
|
631
|
|
|
|
|
|
|
| |
|
632
|
|
|
|
|
|
|
\* [\s\S]*? \*/ # C style |
|
633
|
|
|
|
|
|
|
) # (1) |
|
634
|
|
|
|
|
|
|
| '((?:[^\\\']|\\.)+)' # (2) Character constants |
|
635
|
|
|
|
|
|
|
| "((?:[^\\\"]|\\.)*)" # (3) Strings |
|
636
|
|
|
|
|
|
|
| ( ^ \s* \# .* # (4) Preprocessor |
|
637
|
|
|
|
|
|
|
( \\ $ \n .* )* ) # and continuation lines |
|
638
|
|
|
|
|
|
|
} { |
|
639
|
|
|
|
|
|
|
# We want to preserve the length, so that one may go back |
|
640
|
110
|
0
|
|
|
|
2342
|
defined $1 ? ' ' x (1 + length $1) : |
|
|
|
0
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
defined $4 ? ' ' x length $4 : |
|
642
|
|
|
|
|
|
|
defined $2 ? "'" . ' ' x length($2) . "'" : |
|
643
|
|
|
|
|
|
|
defined $3 ? '"' . ' ' x length($3) . '"' : '???' |
|
644
|
|
|
|
|
|
|
}xgem ; |
|
645
|
2
|
50
|
|
|
|
53
|
die "Unfinished comment" if $in =~ m{ /\* }x; |
|
646
|
2
|
|
|
|
|
54
|
$in; |
|
647
|
|
|
|
|
|
|
} |
|
648
|
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
sub top_level { # We expect argument is sanitized |
|
650
|
|
|
|
|
|
|
# Note that this may remove the variable in declaration: int (*func)(); |
|
651
|
3
|
|
|
3
|
0
|
53
|
my $in = shift; |
|
652
|
3
|
|
|
|
|
11
|
my $start; |
|
653
|
3
|
|
|
|
|
19
|
my $out = $in; |
|
654
|
3
|
|
|
|
|
40
|
while ($in =~ /[\[\{\(]/g ) { |
|
655
|
28
|
|
|
|
|
51
|
$start = pos $in; |
|
656
|
28
|
|
|
|
|
91
|
matchingbrace($in); |
|
657
|
28
|
|
|
|
|
247
|
substr($out, $start, pos($in) - 1 - $start) |
|
658
|
|
|
|
|
|
|
= ' ' x (pos($in) - 1 - $start); |
|
659
|
|
|
|
|
|
|
} |
|
660
|
3
|
|
|
|
|
47
|
$out; |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub remove_type_decl { # We suppose that the arg is top-level only. |
|
664
|
1
|
|
|
1
|
0
|
312
|
my $in = shift; |
|
665
|
1
|
|
|
|
|
26
|
$in =~ s/(\b__extension__)(\s+typedef\b)/(' ' x length $1) . $2/gse; |
|
|
2
|
|
|
|
|
50
|
|
|
666
|
1
|
|
|
|
|
15
|
$in =~ s/(\btypedef\b.*?;)/' ' x length $1/gse; |
|
|
81
|
|
|
|
|
618
|
|
|
667
|
|
|
|
|
|
|
# The following form may appear only in the declaration of the type itself: |
|
668
|
1
|
|
|
|
|
109
|
$in =~ |
|
669
|
1
|
|
|
|
|
9
|
s/(\b(enum|struct|union|class)\b[\s\w]*\{\s*\}\s*;)/' ' x length $1/gse; |
|
670
|
|
|
|
|
|
|
# Pre-declarations: |
|
671
|
1
|
|
|
|
|
115
|
$in =~ |
|
672
|
1
|
|
|
|
|
13
|
s/(\b(enum|struct|union|class)\b[\s\w]*;)/' ' x length $1/gse; |
|
673
|
1
|
|
|
|
|
24
|
$in; |
|
674
|
|
|
|
|
|
|
} |
|
675
|
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
sub new { |
|
677
|
3
|
|
|
3
|
0
|
35628
|
my $class = shift; |
|
678
|
3
|
|
|
|
|
68
|
my $out = SUPER::new $class $recipes; |
|
679
|
3
|
|
|
|
|
62
|
$out->set(@_); |
|
680
|
3
|
|
|
|
|
64
|
$out; |
|
681
|
|
|
|
|
|
|
} |
|
682
|
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
sub do_declarations { |
|
684
|
1
|
|
|
1
|
0
|
141
|
my @d = map do_declaration($_, $_[1], $_[2]), @{ $_[0] }; |
|
|
1
|
|
|
|
|
17
|
|
|
685
|
1
|
|
|
|
|
13
|
\@d; |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
# Forth argument: if defined, there maybe no identifier. Generate one |
|
689
|
|
|
|
|
|
|
# basing on this argument. |
|
690
|
|
|
|
|
|
|
|
|
691
|
|
|
|
|
|
|
sub do_declaration { |
|
692
|
1
|
|
|
1
|
0
|
5
|
my ($decl, $typedefs, $keywords, $argnum) = @_; |
|
693
|
1
|
|
|
|
|
51
|
$decl =~ s/;?\s*$//; |
|
694
|
1
|
|
|
|
|
3
|
my ($type, $typepre, $typepost, $ident, $args, $w, $pos, $repeater); |
|
695
|
1
|
|
|
|
|
19
|
$decl =~ s/^\s*extern\b\s*//; |
|
696
|
1
|
|
|
|
|
3
|
$pos = 0; |
|
697
|
1
|
|
66
|
|
|
49
|
while ($decl =~ /(\w+)/g and ($typedefs->{$1} or $keywords->{$1})) { |
|
|
|
|
33
|
|
|
|
|
|
698
|
1
|
|
|
|
|
4
|
$w = $1; |
|
699
|
1
|
50
|
|
|
|
18
|
if ($w =~ /^(struct|class|enum|union)$/) { |
|
700
|
0
|
0
|
|
|
|
0
|
$decl =~ /\G\s+\w+/g or die "`$w' is not followed by word in `$decl'"; |
|
701
|
|
|
|
|
|
|
} |
|
702
|
1
|
|
|
|
|
16
|
$pos = pos $decl; |
|
703
|
|
|
|
|
|
|
} |
|
704
|
1
|
|
|
|
|
9
|
pos $decl = $pos; |
|
705
|
1
|
50
|
|
|
|
15
|
$decl =~ /\G[\s*]*\*/g or pos $decl = $pos; |
|
706
|
1
|
|
|
|
|
5
|
$type = substr $decl, 0, pos $decl; |
|
707
|
1
|
50
|
|
|
|
7
|
$decl =~ /\G\s*/g or pos $decl = length $type; # ???? |
|
708
|
1
|
|
|
|
|
3
|
$pos = pos $decl; |
|
709
|
1
|
50
|
|
|
|
9
|
if (defined $argnum) { |
|
710
|
0
|
0
|
|
|
|
0
|
if ($decl =~ /\G(\w+)((\s*\[[^][]*\])*)/g) { # The best we can do with [2] |
|
711
|
0
|
|
|
|
|
0
|
$ident = $1; |
|
712
|
0
|
|
|
|
|
0
|
$repeater = $2; |
|
713
|
0
|
|
|
|
|
0
|
$pos = pos $decl; |
|
714
|
|
|
|
|
|
|
} else { |
|
715
|
0
|
|
|
|
|
0
|
pos $decl = $pos = length $decl; |
|
716
|
0
|
|
|
|
|
0
|
$type = $decl; |
|
717
|
0
|
|
|
|
|
0
|
$ident = "arg$argnum"; |
|
718
|
|
|
|
|
|
|
} |
|
719
|
|
|
|
|
|
|
} else { |
|
720
|
1
|
50
|
|
|
|
11
|
die "Cannot process declaration `$decl' without an identifier" |
|
721
|
|
|
|
|
|
|
unless $decl =~ /\G(\w+)/g; |
|
722
|
1
|
|
|
|
|
3
|
$ident = $1; |
|
723
|
1
|
|
|
|
|
3
|
$pos = pos $decl; |
|
724
|
|
|
|
|
|
|
} |
|
725
|
1
|
50
|
|
|
|
8
|
$decl =~ /\G\s*/g or pos $decl = $pos; |
|
726
|
1
|
|
|
|
|
4
|
$pos = pos $decl; |
|
727
|
1
|
50
|
|
|
|
8
|
if (pos $decl != length $decl) { |
|
728
|
1
|
|
|
|
|
5
|
pos $decl = $pos; |
|
729
|
1
|
50
|
|
|
|
12
|
die "Expecting parenth after identifier in `$decl'\nafter `", |
|
730
|
|
|
|
|
|
|
substr($decl, 0, $pos), "'" |
|
731
|
|
|
|
|
|
|
unless $decl =~ /\G\(/g; |
|
732
|
1
|
|
|
|
|
5
|
my $argstring = substr($decl, pos($decl) - length $decl); |
|
733
|
1
|
50
|
|
|
|
15
|
matchingbrace($argstring) or die "Cannot find matching parenth in `$decl'"; |
|
734
|
1
|
|
|
|
|
5
|
$argstring = substr($argstring, 0, pos($argstring) - 1); |
|
735
|
1
|
|
|
|
|
6
|
$argstring =~ s/ ^ ( \s* void )? \s* $ //x; |
|
736
|
1
|
|
|
|
|
3
|
$args = []; |
|
737
|
1
|
|
|
|
|
3
|
my @args; |
|
738
|
1
|
50
|
|
|
|
7
|
if ($argstring ne '') { |
|
739
|
1
|
|
|
|
|
4
|
my $top = top_level $argstring; |
|
740
|
1
|
|
|
|
|
3
|
my $p = 0; |
|
741
|
1
|
|
|
|
|
2
|
my $arg; |
|
742
|
1
|
|
|
|
|
286
|
while ($top =~ /,/g) { |
|
743
|
4
|
|
|
|
|
14
|
$arg = substr($argstring, $p, pos($top) - 1 - $p); |
|
744
|
4
|
|
|
|
|
41
|
$arg =~ s/^\s+|\s+$//gs; |
|
745
|
4
|
|
|
|
|
11
|
push @args, $arg; |
|
746
|
4
|
|
|
|
|
16
|
$p = pos $top; |
|
747
|
|
|
|
|
|
|
} |
|
748
|
1
|
|
|
|
|
11
|
$arg = substr $argstring, $p; |
|
749
|
1
|
|
|
|
|
17
|
$arg =~ s/^\s+|\s+$//gs; |
|
750
|
1
|
|
|
|
|
6
|
push @args, $arg; |
|
751
|
|
|
|
|
|
|
} |
|
752
|
1
|
|
|
|
|
3
|
my $i = 0; |
|
753
|
1
|
|
|
|
|
4
|
for (@args) { |
|
754
|
5
|
|
|
|
|
22
|
push @$args, do_declaration1($_, $typedefs, $keywords, $i++); |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
} |
|
757
|
1
|
|
|
|
|
8
|
[$type, $ident, $args, $decl, $repeater]; |
|
758
|
|
|
|
|
|
|
} |
|
759
|
|
|
|
|
|
|
|
|
760
|
|
|
|
|
|
|
sub do_declaration1 { |
|
761
|
5
|
|
|
5
|
0
|
14
|
my ($decl, $typedefs, $keywords, $argnum) = @_; |
|
762
|
5
|
|
|
|
|
59
|
$decl =~ s/;?\s*$//; |
|
763
|
5
|
|
|
|
|
16
|
my ($type, $typepre, $typepost, $ident, $args, $w, $pos, $repeater); |
|
764
|
5
|
|
|
|
|
9
|
$pos = 0; |
|
765
|
5
|
|
100
|
|
|
77
|
while ($decl =~ /(\w+)/g and ($typedefs->{$1} or $keywords->{$1})) { |
|
|
|
|
33
|
|
|
|
|
|
766
|
5
|
|
|
|
|
13
|
$w = $1; |
|
767
|
5
|
100
|
|
|
|
23
|
if ($w =~ /^(struct|class|enum|union)$/) { |
|
768
|
1
|
50
|
|
|
|
9
|
$decl =~ /\G\s+\w+/g or die "`$w' is not followed by word in `$decl'"; |
|
769
|
|
|
|
|
|
|
} |
|
770
|
5
|
|
|
|
|
66
|
$pos = pos $decl; |
|
771
|
|
|
|
|
|
|
} |
|
772
|
5
|
|
|
|
|
17
|
pos $decl = $pos; |
|
773
|
5
|
100
|
|
|
|
34
|
$decl =~ /\G[\s*]*\*/g or pos $decl = $pos; |
|
774
|
5
|
|
|
|
|
14
|
$type = substr $decl, 0, pos $decl; |
|
775
|
5
|
50
|
|
|
|
32
|
$decl =~ /\G\s*/g or pos $decl = length $type; # ???? |
|
776
|
5
|
|
|
|
|
9
|
$pos = pos $decl; |
|
777
|
5
|
50
|
|
|
|
14
|
if (defined $argnum) { |
|
778
|
5
|
50
|
|
|
|
29
|
if ($decl =~ /\G(\w+)((\s*\[[^][]*\])*)/g) { # The best we can do with [2] |
|
779
|
5
|
|
|
|
|
19
|
$ident = $1; |
|
780
|
5
|
|
|
|
|
14
|
$repeater = $2; |
|
781
|
5
|
|
|
|
|
11
|
$pos = pos $decl; |
|
782
|
|
|
|
|
|
|
} else { |
|
783
|
0
|
|
|
|
|
0
|
pos $decl = $pos = length $decl; |
|
784
|
0
|
|
|
|
|
0
|
$type = $decl; |
|
785
|
0
|
|
|
|
|
0
|
$ident = "arg$argnum"; |
|
786
|
|
|
|
|
|
|
} |
|
787
|
|
|
|
|
|
|
} else { |
|
788
|
0
|
0
|
|
|
|
0
|
die "Cannot process declaration `$decl' without an identifier" |
|
789
|
|
|
|
|
|
|
unless $decl =~ /\G(\w+)/g; |
|
790
|
0
|
|
|
|
|
0
|
$ident = $1; |
|
791
|
0
|
|
|
|
|
0
|
$pos = pos $decl; |
|
792
|
|
|
|
|
|
|
} |
|
793
|
5
|
50
|
|
|
|
22
|
$decl =~ /\G\s*/g or pos $decl = $pos; |
|
794
|
5
|
|
|
|
|
10
|
$pos = pos $decl; |
|
795
|
5
|
50
|
|
|
|
18
|
if (pos $decl != length $decl) { |
|
796
|
0
|
|
|
|
|
0
|
pos $decl = $pos; |
|
797
|
0
|
0
|
|
|
|
0
|
die "Expecting parenth after identifier in `$decl'\nafter `", |
|
798
|
|
|
|
|
|
|
substr($decl, 0, $pos), "'" |
|
799
|
|
|
|
|
|
|
unless $decl =~ /\G\(/g; |
|
800
|
0
|
|
|
|
|
0
|
my $argstring = substr($decl, pos($decl) - length $decl); |
|
801
|
0
|
0
|
|
|
|
0
|
matchingbrace($argstring) or die "Cannot find matching parenth in `$decl'"; |
|
802
|
0
|
|
|
|
|
0
|
$argstring = substr($argstring, 0, pos($argstring) - 1); |
|
803
|
0
|
|
|
|
|
0
|
$argstring =~ s/ ^ ( \s* void )? \s* $ //x; |
|
804
|
0
|
|
|
|
|
0
|
$args = []; |
|
805
|
0
|
|
|
|
|
0
|
my @args; |
|
806
|
0
|
0
|
|
|
|
0
|
if ($argstring ne '') { |
|
807
|
0
|
|
|
|
|
0
|
my $top = top_level $argstring; |
|
808
|
0
|
|
|
|
|
0
|
my $p = 0; |
|
809
|
0
|
|
|
|
|
0
|
my $arg; |
|
810
|
0
|
|
|
|
|
0
|
while ($top =~ /,/g) { |
|
811
|
0
|
|
|
|
|
0
|
$arg = substr($argstring, $p, pos($top) - 1 - $p); |
|
812
|
0
|
|
|
|
|
0
|
$arg =~ s/^\s+|\s+$//gs; |
|
813
|
0
|
|
|
|
|
0
|
push @args, $arg; |
|
814
|
0
|
|
|
|
|
0
|
$p = pos $top; |
|
815
|
|
|
|
|
|
|
} |
|
816
|
0
|
|
|
|
|
0
|
$arg = substr $argstring, $p; |
|
817
|
0
|
|
|
|
|
0
|
$arg =~ s/^\s+|\s+$//gs; |
|
818
|
0
|
|
|
|
|
0
|
push @args, $arg; |
|
819
|
|
|
|
|
|
|
} |
|
820
|
0
|
|
|
|
|
0
|
my $i = 0; |
|
821
|
0
|
|
|
|
|
0
|
for (@args) { |
|
822
|
0
|
|
|
|
|
0
|
push @$args, do_declaration2($_, $typedefs, $keywords, $i++); |
|
823
|
|
|
|
|
|
|
} |
|
824
|
|
|
|
|
|
|
} |
|
825
|
5
|
|
|
|
|
37
|
[$type, $ident, $args, $decl, $repeater]; |
|
826
|
|
|
|
|
|
|
} |
|
827
|
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
############################################################ |
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
package C::Preprocessed; |
|
831
|
1
|
|
|
1
|
|
1007
|
use Symbol; |
|
|
1
|
|
|
|
|
1128
|
|
|
|
1
|
|
|
|
|
105
|
|
|
832
|
1
|
|
|
1
|
|
8
|
use File::Basename; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
64
|
|
|
833
|
1
|
|
|
1
|
|
7
|
use Config; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
634
|
|
|
834
|
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
sub new { |
|
836
|
5
|
50
|
33
|
5
|
|
56
|
die "usage: C::Preprocessed->new(filename[, defines[, includes[, cpp]]])" |
|
837
|
|
|
|
|
|
|
if @_ < 2 or @_ > 5; |
|
838
|
5
|
|
|
|
|
18
|
my ($class, $filename, $Defines, $Includes, $Cpp) |
|
839
|
|
|
|
|
|
|
= (shift, shift, shift, shift, shift); |
|
840
|
5
|
|
50
|
|
|
14
|
$Cpp ||= \%Config::Config; |
|
841
|
5
|
|
50
|
|
|
272
|
my $filedir = dirname $filename || '.'; |
|
842
|
5
|
|
50
|
|
|
13
|
$Includes ||= [$filedir, '/usr/local/include', '.']; |
|
843
|
5
|
|
|
|
|
16
|
my $addincludes = ""; |
|
844
|
5
|
50
|
33
|
|
|
56
|
$addincludes = "-I" . join(" -I", @$Includes) |
|
845
|
|
|
|
|
|
|
if defined $Includes and @$Includes; |
|
846
|
5
|
|
|
|
|
24
|
my($sym) = gensym; |
|
847
|
5
|
|
|
|
|
179
|
my $cmd = "echo '\#include \"$filename\"' | $Cpp->{cppstdin} $Defines $addincludes $Cpp->{cppflags} $Cpp->{cppminus} |"; |
|
848
|
|
|
|
|
|
|
#my $cmd = "$Cpp->{cppstdin} $Defines $addincludes $Cpp->{cppflags} $Cpp->{cppminus} < $filename |"; |
|
849
|
|
|
|
|
|
|
#my $cmd = "echo '\#include <$filename>' | $Cpp->{cppstdin} $Defines $addincludes $Cpp->{cppflags} $Cpp->{cppminus} |"; |
|
850
|
|
|
|
|
|
|
|
|
851
|
5
|
50
|
50
|
|
|
29803
|
(open($sym, $cmd) or die "Cannot open pipe from `$cmd': $!") |
|
852
|
|
|
|
|
|
|
and bless $sym => $class; |
|
853
|
|
|
|
|
|
|
} |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
sub text { |
|
856
|
2
|
|
|
2
|
|
482
|
my $class = shift; |
|
857
|
2
|
|
|
|
|
3
|
my $filter = shift; |
|
858
|
2
|
50
|
|
|
|
6
|
if (defined $filter) { |
|
859
|
0
|
|
|
|
|
0
|
return text_only_from($class, $filter, @_); |
|
860
|
|
|
|
|
|
|
} |
|
861
|
2
|
|
|
|
|
16
|
my $stream = $class->new(@_); |
|
862
|
2
|
|
|
|
|
57
|
my $oh = select $stream; |
|
863
|
2
|
|
|
|
|
33
|
$/ = undef; |
|
864
|
2
|
|
|
|
|
20
|
select $oh; |
|
865
|
2
|
|
|
|
|
61066
|
<$stream>; |
|
866
|
|
|
|
|
|
|
} |
|
867
|
|
|
|
|
|
|
|
|
868
|
|
|
|
|
|
|
sub text_only_from { |
|
869
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
|
870
|
0
|
|
0
|
|
|
0
|
my $from = shift || die "Expecting argument in `text_only_from'"; |
|
871
|
0
|
|
|
|
|
0
|
my $stream = $class->new(@_); |
|
872
|
0
|
|
|
|
|
0
|
my $on = $from eq $_[0]; |
|
873
|
0
|
0
|
|
|
|
0
|
my $eqregexp = $on ? '\"\"|' : ''; |
|
874
|
0
|
|
|
|
|
0
|
my @out; |
|
875
|
0
|
|
|
|
|
0
|
while (<$stream>) { |
|
876
|
|
|
|
|
|
|
#print; |
|
877
|
|
|
|
|
|
|
|
|
878
|
0
|
0
|
|
|
|
0
|
$on = /$eqregexp[\"\/]\Q$from\"/ if /^\#/; |
|
879
|
0
|
0
|
|
|
|
0
|
push @out, $_ if $on; |
|
880
|
|
|
|
|
|
|
} |
|
881
|
0
|
|
|
|
|
0
|
join '', @out; |
|
882
|
|
|
|
|
|
|
} |
|
883
|
|
|
|
|
|
|
|
|
884
|
|
|
|
|
|
|
sub DESTROY { |
|
885
|
5
|
50
|
|
5
|
|
710
|
close($_[0]) |
|
886
|
|
|
|
|
|
|
or die "Cannot close pipe from `$Config::Config{cppstdin}': err $?, $!\n"; |
|
887
|
|
|
|
|
|
|
} |
|
888
|
|
|
|
|
|
|
|
|
889
|
|
|
|
|
|
|
# Autoload methods go after __END__, and are processed by the autosplit program. |
|
890
|
|
|
|
|
|
|
# Return to the principal package. |
|
891
|
|
|
|
|
|
|
package C::Scan; |
|
892
|
|
|
|
|
|
|
|
|
893
|
|
|
|
|
|
|
1; |
|
894
|
|
|
|
|
|
|
__END__ |