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