line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package C::Utility; |
2
|
2
|
|
|
2
|
|
140407
|
use warnings; |
|
2
|
|
|
|
|
12
|
|
|
2
|
|
|
|
|
68
|
|
3
|
2
|
|
|
2
|
|
11
|
use strict; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
38
|
|
4
|
2
|
|
|
2
|
|
10
|
use File::Spec; |
|
2
|
|
|
|
|
3
|
|
|
2
|
|
|
|
|
48
|
|
5
|
2
|
|
|
2
|
|
10
|
use Carp; |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
148
|
|
6
|
2
|
|
|
2
|
|
1003
|
use File::Versions 'make_backup'; |
|
2
|
|
|
|
|
2459
|
|
|
2
|
|
|
|
|
120
|
|
7
|
2
|
|
|
2
|
|
913
|
use File::Slurper qw/read_text write_text/; |
|
2
|
|
|
|
|
28625
|
|
|
2
|
|
|
|
|
148
|
|
8
|
2
|
|
|
2
|
|
975
|
use C::Tokenize qw/$comment_re $include $reserved_re/; |
|
2
|
|
|
|
|
8894
|
|
|
2
|
|
|
|
|
340
|
|
9
|
2
|
|
|
2
|
|
957
|
use Text::LineNumber; |
|
2
|
|
|
|
|
709
|
|
|
2
|
|
|
|
|
4581
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
require Exporter; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @EXPORT_OK = qw/ |
16
|
|
|
|
|
|
|
add_lines |
17
|
|
|
|
|
|
|
brute_force_line |
18
|
|
|
|
|
|
|
c_string |
19
|
|
|
|
|
|
|
c_to_h_name |
20
|
|
|
|
|
|
|
ch_files |
21
|
|
|
|
|
|
|
convert_to_c_string |
22
|
|
|
|
|
|
|
convert_to_c_string_pc |
23
|
|
|
|
|
|
|
escape_string |
24
|
|
|
|
|
|
|
hash_to_c_file |
25
|
|
|
|
|
|
|
line_directive |
26
|
|
|
|
|
|
|
linein |
27
|
|
|
|
|
|
|
lineout |
28
|
|
|
|
|
|
|
print_bottom_h_wrapper |
29
|
|
|
|
|
|
|
print_top_h_wrapper |
30
|
|
|
|
|
|
|
read_includes |
31
|
|
|
|
|
|
|
remove_quotes |
32
|
|
|
|
|
|
|
stamp_file |
33
|
|
|
|
|
|
|
valid_c_variable |
34
|
|
|
|
|
|
|
/; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
our %EXPORT_TAGS = ( |
37
|
|
|
|
|
|
|
'all' => \@EXPORT_OK, |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
our $VERSION = '0.011'; |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub convert_to_c_string |
43
|
|
|
|
|
|
|
{ |
44
|
2
|
|
|
2
|
1
|
88
|
my ($text) = @_; |
45
|
2
|
50
|
|
|
|
9
|
if (length ($text) == 0) { |
46
|
0
|
|
|
|
|
0
|
return "\"\""; |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
# Convert backslashes to double backslashes. |
49
|
2
|
|
|
|
|
5
|
$text =~ s/\\/\\\\/g; |
50
|
|
|
|
|
|
|
# Escape double quotes |
51
|
2
|
|
|
|
|
6
|
$text = escape_string ($text); |
52
|
|
|
|
|
|
|
# If there was a backslash before a quote, as in \", the first |
53
|
|
|
|
|
|
|
# regex above converted it to \\", and then escape_string |
54
|
|
|
|
|
|
|
# converted that to \\\". |
55
|
2
|
|
|
|
|
5
|
$text =~ s/\\\\"/\\"/g; |
56
|
|
|
|
|
|
|
# Remove backslashes from before the @ symbol. |
57
|
2
|
|
|
|
|
4
|
$text =~ s/\\\@/@/g; |
58
|
|
|
|
|
|
|
# Turn each line into a string |
59
|
2
|
|
|
|
|
11
|
$text =~ s/(.*)\n/"$1\\n"\n/gm; |
60
|
|
|
|
|
|
|
# Catch a final line without any \n at its end. |
61
|
2
|
100
|
|
|
|
8
|
if ($text !~ /\\n\"$/) { |
62
|
1
|
|
|
|
|
10
|
$text =~ s/(.+)$/"$1"/g; |
63
|
|
|
|
|
|
|
} |
64
|
2
|
|
|
|
|
6
|
return $text; |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
sub c_string |
68
|
|
|
|
|
|
|
{ |
69
|
0
|
|
|
0
|
1
|
0
|
goto & convert_to_c_string; |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
sub ch_files |
73
|
|
|
|
|
|
|
{ |
74
|
0
|
|
|
0
|
1
|
0
|
my ($c_file_name) = @_; |
75
|
0
|
0
|
|
|
|
0
|
if ($c_file_name !~ /\.c/) { |
76
|
0
|
|
|
|
|
0
|
die "$c_file_name is not a C file name"; |
77
|
|
|
|
|
|
|
} |
78
|
0
|
|
|
|
|
0
|
my $h_file_name = $c_file_name; |
79
|
0
|
|
|
|
|
0
|
$h_file_name =~ s/\.c$/\.h/; |
80
|
0
|
0
|
|
|
|
0
|
if (-f $c_file_name) { |
81
|
0
|
|
|
|
|
0
|
make_backup ($c_file_name); |
82
|
|
|
|
|
|
|
} |
83
|
0
|
0
|
|
|
|
0
|
if (-f $h_file_name) { |
84
|
0
|
|
|
|
|
0
|
make_backup ($h_file_name); |
85
|
|
|
|
|
|
|
} |
86
|
0
|
|
|
|
|
0
|
return $h_file_name; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
sub convert_to_c_string_pc |
90
|
|
|
|
|
|
|
{ |
91
|
1
|
|
|
1
|
1
|
456
|
my ($text) = @_; |
92
|
1
|
|
|
|
|
6
|
$text =~ s/%/%%/g; |
93
|
1
|
|
|
|
|
3
|
return convert_to_c_string ($text); |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub escape_string |
97
|
|
|
|
|
|
|
{ |
98
|
2
|
|
|
2
|
1
|
4
|
my ($text) = @_; |
99
|
2
|
|
|
|
|
5
|
$text =~ s/\"/\\\"/g; |
100
|
2
|
|
|
|
|
5
|
return $text; |
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub c_to_h_name |
104
|
|
|
|
|
|
|
{ |
105
|
0
|
|
|
0
|
1
|
0
|
my ($c_file_name) = @_; |
106
|
0
|
0
|
|
|
|
0
|
if ($c_file_name !~ /\.c/) { |
107
|
0
|
|
|
|
|
0
|
die "$c_file_name is not a C file name"; |
108
|
|
|
|
|
|
|
} |
109
|
0
|
|
|
|
|
0
|
my $h_file_name = $c_file_name; |
110
|
0
|
|
|
|
|
0
|
$h_file_name =~ s/\.c$/\.h/; |
111
|
0
|
|
|
|
|
0
|
return $h_file_name; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
sub valid_c_variable |
115
|
|
|
|
|
|
|
{ |
116
|
0
|
|
|
0
|
1
|
0
|
my ($variable_name) = @_; |
117
|
0
|
0
|
0
|
|
|
0
|
if ($variable_name !~ /^[A-Za-z_][A-Za-z_0-9]+$/ || |
118
|
|
|
|
|
|
|
$variable_name =~ /^(?:$reserved_re)$/) { |
119
|
0
|
|
|
|
|
0
|
return; |
120
|
|
|
|
|
|
|
} |
121
|
0
|
|
|
|
|
0
|
return 1; |
122
|
|
|
|
|
|
|
} |
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
# Wrapper name |
125
|
|
|
|
|
|
|
# BKB 2009-10-05 14:09:41 |
126
|
|
|
|
|
|
|
|
127
|
|
|
|
|
|
|
sub wrapper_name |
128
|
|
|
|
|
|
|
{ |
129
|
0
|
|
|
0
|
1
|
0
|
my ($string) = @_; |
130
|
0
|
|
|
|
|
0
|
$string =~ s/[.-]/_/g; |
131
|
0
|
0
|
|
|
|
0
|
if (! valid_c_variable ($string)) { |
132
|
0
|
|
|
|
|
0
|
croak "Bad string for wrapper '$string'"; |
133
|
|
|
|
|
|
|
} |
134
|
0
|
|
|
|
|
0
|
my $wrapper_name = uc $string; |
135
|
0
|
|
|
|
|
0
|
return $wrapper_name; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub print_top_h_wrapper |
139
|
|
|
|
|
|
|
{ |
140
|
0
|
|
|
0
|
1
|
0
|
my ($fh, $file_name) = @_; |
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
0
|
my $wrapper_name = wrapper_name ($file_name); |
143
|
0
|
|
|
|
|
0
|
my $wrapper = <
|
144
|
|
|
|
|
|
|
#ifndef $wrapper_name |
145
|
|
|
|
|
|
|
#define $wrapper_name |
146
|
|
|
|
|
|
|
EOF |
147
|
0
|
|
|
|
|
0
|
print_out ($fh, $wrapper); |
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
sub print_out |
151
|
|
|
|
|
|
|
{ |
152
|
0
|
|
|
0
|
0
|
0
|
my ($fh, $wrapper) = @_; |
153
|
0
|
0
|
0
|
|
|
0
|
if (ref $fh && ref $fh eq 'SCALAR') { |
154
|
0
|
|
|
|
|
0
|
${$fh} .= $wrapper; |
|
0
|
|
|
|
|
0
|
|
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
else { |
157
|
0
|
|
|
|
|
0
|
print $fh $wrapper; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub print_bottom_h_wrapper |
162
|
|
|
|
|
|
|
{ |
163
|
0
|
|
|
0
|
1
|
0
|
my ($fh, $file_name) = @_; |
164
|
0
|
|
|
|
|
0
|
my $wrapper_name = wrapper_name ($file_name); |
165
|
0
|
|
|
|
|
0
|
my $wrapper = <
|
166
|
|
|
|
|
|
|
#endif /* $wrapper_name */ |
167
|
|
|
|
|
|
|
EOF |
168
|
0
|
|
|
|
|
0
|
print_out ($fh, $wrapper); |
169
|
|
|
|
|
|
|
} |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
sub print_include |
172
|
|
|
|
|
|
|
{ |
173
|
0
|
|
|
0
|
1
|
0
|
my ($fh, $h_file_name) = @_; |
174
|
0
|
|
|
|
|
0
|
print $fh <
|
175
|
|
|
|
|
|
|
#include "$h_file_name" |
176
|
|
|
|
|
|
|
EOF |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
sub hash_to_c_file |
180
|
|
|
|
|
|
|
{ |
181
|
|
|
|
|
|
|
# $prefix is an optional prefix applied to all variables. |
182
|
0
|
|
|
0
|
1
|
0
|
my ($c_file_name, $hash_ref, $prefix) = @_; |
183
|
0
|
|
|
|
|
0
|
my $h_file_name = ch_files ($c_file_name); |
184
|
0
|
0
|
|
|
|
0
|
die "Not a hash ref" unless ref $hash_ref eq "HASH"; |
185
|
0
|
0
|
|
|
|
0
|
$prefix = "" unless $prefix; |
186
|
0
|
0
|
|
|
|
0
|
open my $c_out, ">:utf8", $c_file_name or die $!; |
187
|
0
|
|
|
|
|
0
|
my (undef, undef, $h_file) = File::Spec->splitpath ($h_file_name); |
188
|
0
|
|
|
|
|
0
|
print_include ($c_out, $h_file); |
189
|
0
|
0
|
|
|
|
0
|
open my $h_out, ">:utf8", $h_file_name or die $!; |
190
|
0
|
|
|
|
|
0
|
print_top_h_wrapper ($h_out, $h_file); |
191
|
0
|
|
|
|
|
0
|
for my $variable (sort keys %$hash_ref) { |
192
|
0
|
0
|
|
|
|
0
|
if (! valid_c_variable ($variable)) { |
193
|
0
|
|
|
|
|
0
|
croak "key '$variable' is not a valid C variable"; |
194
|
|
|
|
|
|
|
} |
195
|
0
|
|
|
|
|
0
|
my $value = $hash_ref->{$variable}; |
196
|
0
|
|
|
|
|
0
|
$value = convert_to_c_string ($value); |
197
|
0
|
|
|
|
|
0
|
print $c_out "const char * $prefix$variable = $value;\n"; |
198
|
0
|
|
|
|
|
0
|
print $h_out "extern const char * $prefix$variable; /* $value */\n"; |
199
|
|
|
|
|
|
|
} |
200
|
0
|
0
|
|
|
|
0
|
close $c_out or die $!; |
201
|
0
|
|
|
|
|
0
|
print_bottom_h_wrapper ($h_out, $h_file); |
202
|
0
|
0
|
|
|
|
0
|
close $h_out or die $!; |
203
|
0
|
|
|
|
|
0
|
return $h_file_name; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
sub line_directive |
207
|
|
|
|
|
|
|
{ |
208
|
0
|
|
|
0
|
1
|
0
|
my ($output, $line_number, $file_name) = @_; |
209
|
0
|
0
|
0
|
|
|
0
|
die "$line_number is not a positive integer number" |
210
|
|
|
|
|
|
|
unless $line_number =~ /^[0-9]+$/ && $line_number > 0; |
211
|
0
|
|
|
|
|
0
|
print_out ($output, "#line $line_number \"$file_name\"\n"); |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub brute_force_line |
215
|
|
|
|
|
|
|
{ |
216
|
0
|
|
|
0
|
1
|
0
|
my ($input_file, $output_file) = @_; |
217
|
0
|
0
|
|
|
|
0
|
open my $input, "<:encoding(utf8)", $input_file or die $!; |
218
|
0
|
0
|
|
|
|
0
|
open my $output, ">:encoding(utf8)", $output_file or die $!; |
219
|
0
|
|
|
|
|
0
|
while (<$input>) { |
220
|
0
|
|
|
|
|
0
|
print $output "#line $. \"$input_file\"\n"; |
221
|
0
|
|
|
|
|
0
|
print $output $_; |
222
|
|
|
|
|
|
|
} |
223
|
0
|
0
|
|
|
|
0
|
close $input or die $!; |
224
|
0
|
0
|
|
|
|
0
|
close $output or die $!; |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
sub add_lines |
228
|
|
|
|
|
|
|
{ |
229
|
0
|
|
|
0
|
1
|
0
|
my ($input_file) = @_; |
230
|
0
|
|
|
|
|
0
|
my $full_name = File::Spec->rel2abs ($input_file); |
231
|
0
|
|
|
|
|
0
|
my $text = ''; |
232
|
0
|
0
|
|
|
|
0
|
open my $input, "<:encoding(utf8)", $input_file or die $!; |
233
|
0
|
|
|
|
|
0
|
while (<$input>) { |
234
|
0
|
0
|
|
|
|
0
|
if (/^#line/) { |
|
|
0
|
|
|
|
|
|
235
|
0
|
|
|
|
|
0
|
my $line_no = $. + 1; |
236
|
0
|
|
|
|
|
0
|
$text .= "#line $line_no \"$full_name\"\n"; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
elsif ($. == 1) { |
239
|
0
|
|
|
|
|
0
|
$text .= "#line 1 \"$full_name\"\n"; |
240
|
0
|
|
|
|
|
0
|
$text .= $_; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
else { |
243
|
0
|
|
|
|
|
0
|
$text .= $_; |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
} |
246
|
0
|
|
|
|
|
0
|
return $text; |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
sub remove_quotes |
250
|
|
|
|
|
|
|
{ |
251
|
3
|
|
|
3
|
1
|
93
|
my ($string) = @_; |
252
|
3
|
|
|
|
|
25
|
$string =~ s/^"|"$|"\s*"//g; |
253
|
3
|
|
|
|
|
15
|
return $string; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
#use Data::Dumper; |
256
|
|
|
|
|
|
|
sub linedirective |
257
|
|
|
|
|
|
|
{ |
258
|
0
|
|
|
0
|
0
|
|
my ($intext, $file, $directive) = @_; |
259
|
0
|
0
|
0
|
|
|
|
die unless $intext && $file && $directive; |
|
|
|
0
|
|
|
|
|
260
|
|
|
|
|
|
|
# This module is pretty reliable for line numbering. |
261
|
0
|
|
|
|
|
|
my $tln = Text::LineNumber->new ($intext); |
262
|
0
|
|
|
|
|
|
my %renumbered; |
263
|
|
|
|
|
|
|
# Uniquifier for the lines. |
264
|
0
|
|
|
|
|
|
my $count = 0; |
265
|
|
|
|
|
|
|
# This is unlikely to occur. |
266
|
0
|
|
|
|
|
|
my $tag = 'ABRACADABRA'; |
267
|
|
|
|
|
|
|
# Watch for blue-moon occurences |
268
|
0
|
0
|
|
|
|
|
die if $intext =~ /$tag\d+/; |
269
|
0
|
|
|
|
|
|
while ($intext =~ s/^\Q$directive/$tag$count$tag/sm) { |
270
|
0
|
|
|
|
|
|
$count++; |
271
|
|
|
|
|
|
|
} |
272
|
|
|
|
|
|
|
# "pos" doesn't work well with s///g, so now we need to match the tags |
273
|
|
|
|
|
|
|
# one by one. |
274
|
0
|
|
|
|
|
|
while ($intext =~ /($tag\d+$tag)/g) { |
275
|
0
|
|
|
|
|
|
my $key = $1; |
276
|
0
|
|
|
|
|
|
my $pos = pos ($intext); |
277
|
0
|
|
|
|
|
|
my $line = $tln->off2lnr ($pos); |
278
|
|
|
|
|
|
|
# print "Position $pos in $file = line $line.\n"; |
279
|
0
|
|
|
|
|
|
$renumbered{$key} = $line; |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
#print Dumper (\%renumbered); |
282
|
0
|
|
|
|
|
|
$intext =~ s/($tag\d+$tag)/#line $renumbered{$1} "$file"/g; |
283
|
|
|
|
|
|
|
# Check for failures. We already checked this doesn't occur |
284
|
|
|
|
|
|
|
# naturally in the file above. |
285
|
0
|
0
|
|
|
|
|
die if $intext =~ /$tag\d+$tag/; |
286
|
0
|
|
|
|
|
|
return $intext; |
287
|
|
|
|
|
|
|
} |
288
|
|
|
|
|
|
|
|
289
|
|
|
|
|
|
|
sub linein |
290
|
|
|
|
|
|
|
{ |
291
|
0
|
|
|
0
|
1
|
|
my ($infile) = @_; |
292
|
0
|
|
|
|
|
|
my $intext = read_text ($infile); |
293
|
0
|
|
|
|
|
|
$intext = linedirective ($intext, $infile, '#linein'); |
294
|
0
|
|
|
|
|
|
return $intext; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
sub lineout |
298
|
|
|
|
|
|
|
{ |
299
|
0
|
|
|
0
|
1
|
|
my ($outtext, $outfile) = @_; |
300
|
|
|
|
|
|
|
|
301
|
0
|
|
|
|
|
|
$outtext = linedirective ($outtext, $outfile, "#lineout"); |
302
|
0
|
|
|
|
|
|
write_text ($outfile, $outtext); |
303
|
|
|
|
|
|
|
} |
304
|
|
|
|
|
|
|
|
305
|
|
|
|
|
|
|
sub stamp_file |
306
|
|
|
|
|
|
|
{ |
307
|
0
|
|
|
0
|
1
|
|
my ($fh, $name) = @_; |
308
|
0
|
0
|
|
|
|
|
if (! defined $name) { |
309
|
0
|
|
|
|
|
|
$name = "This C file"; |
310
|
|
|
|
|
|
|
} |
311
|
0
|
|
|
|
|
|
my $now = scalar localtime (); |
312
|
0
|
|
|
|
|
|
my $stamp =<
|
313
|
|
|
|
|
|
|
/* |
314
|
|
|
|
|
|
|
$name was generated by $0 at $now. |
315
|
|
|
|
|
|
|
*/ |
316
|
|
|
|
|
|
|
EOF |
317
|
0
|
|
|
|
|
|
print_out ($fh, $stamp); |
318
|
|
|
|
|
|
|
} |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
sub read_includes |
321
|
|
|
|
|
|
|
{ |
322
|
0
|
|
|
0
|
1
|
|
my ($file) = @_; |
323
|
0
|
|
|
|
|
|
my $text = read_text ($file); |
324
|
|
|
|
|
|
|
# Remove all the comments from the file so that things like |
325
|
|
|
|
|
|
|
# /*#include "something.h"*/ don't create false positives. |
326
|
0
|
|
|
|
|
|
$text =~ s/$comment_re//g; |
327
|
0
|
|
|
|
|
|
my @hfiles; |
328
|
0
|
|
|
|
|
|
while ($text =~ /$include/g) { |
329
|
0
|
|
|
|
|
|
push @hfiles, $1; |
330
|
|
|
|
|
|
|
} |
331
|
0
|
|
|
|
|
|
return \@hfiles; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
1; |