| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package CSVAWK; # git description: 0.0.1-2-g2eeca26 |
|
2
|
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
6607
|
use strict; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
27
|
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
23
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
1
|
|
|
1
|
|
410
|
use autodie; |
|
|
1
|
|
|
|
|
12025
|
|
|
|
1
|
|
|
|
|
4
|
|
|
7
|
1
|
|
|
1
|
|
6398
|
use charnames qw(:full); |
|
|
1
|
|
|
|
|
26544
|
|
|
|
1
|
|
|
|
|
5
|
|
|
8
|
1
|
|
|
1
|
|
600
|
use English qw(-no_match_vars); |
|
|
1
|
|
|
|
|
2792
|
|
|
|
1
|
|
|
|
|
7
|
|
|
9
|
1
|
|
|
1
|
|
356
|
use File::Basename; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
60
|
|
|
10
|
1
|
|
|
1
|
|
662
|
use File::Temp qw(tempdir tempfile); |
|
|
1
|
|
|
|
|
19129
|
|
|
|
1
|
|
|
|
|
74
|
|
|
11
|
1
|
|
|
1
|
|
580
|
use Readonly; |
|
|
1
|
|
|
|
|
3553
|
|
|
|
1
|
|
|
|
|
55
|
|
|
12
|
1
|
|
|
1
|
|
847
|
use Text::CSV_XS; |
|
|
1
|
|
|
|
|
8969
|
|
|
|
1
|
|
|
|
|
60
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
10
|
use base 'Exporter'; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
91
|
|
|
15
|
|
|
|
|
|
|
our @EXPORT_OK = qw(csvawk); |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
our $VERSION = '0.1'; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
Readonly my $HIDE_FS => "\N{INFORMATION SEPARATOR ONE}"; |
|
20
|
|
|
|
|
|
|
Readonly my $HIDE_RS => "\N{INFORMATION SEPARATOR TWO}"; |
|
21
|
|
|
|
|
|
|
Readonly my %SWITCHES_WITH_PARAMETERS => map { $_ => 1 } qw( |
|
22
|
|
|
|
|
|
|
-f --file |
|
23
|
|
|
|
|
|
|
-F --field-separator |
|
24
|
|
|
|
|
|
|
-v --assign |
|
25
|
|
|
|
|
|
|
-m |
|
26
|
|
|
|
|
|
|
-e --source |
|
27
|
|
|
|
|
|
|
-E --exec |
|
28
|
|
|
|
|
|
|
-i --include |
|
29
|
|
|
|
|
|
|
-l --load |
|
30
|
|
|
|
|
|
|
-W |
|
31
|
|
|
|
|
|
|
); |
|
32
|
|
|
|
|
|
|
Readonly my $IS_PROGRAM_SWITCH => qr/^-[ef]/mxs; |
|
33
|
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub convert_to_identifier { |
|
35
|
0
|
|
|
0
|
0
|
|
my ($str) = @_; |
|
36
|
0
|
|
|
|
|
|
$str =~ s/\W+/_/mxsg; |
|
37
|
0
|
0
|
|
|
|
|
if ( $str !~ m/^[[:alpha:]_]/mxs ) { |
|
38
|
0
|
|
|
|
|
|
$str = "_$str"; |
|
39
|
|
|
|
|
|
|
} |
|
40
|
0
|
|
|
|
|
|
return $str; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
sub get_csv_parser { |
|
44
|
0
|
|
|
0
|
0
|
|
my $csv = Text::CSV_XS->new( |
|
45
|
|
|
|
|
|
|
{ |
|
46
|
|
|
|
|
|
|
binary => 1, |
|
47
|
|
|
|
|
|
|
auto_diag => 1, |
|
48
|
|
|
|
|
|
|
eol => "\n", |
|
49
|
|
|
|
|
|
|
} |
|
50
|
|
|
|
|
|
|
); |
|
51
|
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
|
return $csv; |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub hide_separators { |
|
56
|
0
|
|
|
0
|
0
|
|
my ($str) = @_; |
|
57
|
0
|
|
|
|
|
|
$str =~ s/,/$HIDE_FS/mxsg; |
|
58
|
0
|
|
|
|
|
|
$str =~ s/\n/$HIDE_RS/mxsg; |
|
59
|
0
|
|
|
|
|
|
return $str; |
|
60
|
|
|
|
|
|
|
} |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub restore_separators { |
|
63
|
0
|
|
|
0
|
0
|
|
my ($str) = @_; |
|
64
|
0
|
|
|
|
|
|
$str =~ s/$HIDE_FS/,/mxsg; |
|
65
|
0
|
|
|
|
|
|
$str =~ s/$HIDE_RS/\n/mxsg; |
|
66
|
0
|
|
|
|
|
|
return $str; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub split_arguments { |
|
70
|
0
|
|
|
0
|
0
|
|
my (@args) = @_; |
|
71
|
0
|
|
|
|
|
|
my ( @files, $has_program_switch ); |
|
72
|
|
|
|
|
|
|
|
|
73
|
0
|
|
|
|
|
|
ARGUMENT: for my $arg ( reverse @args ) { |
|
74
|
0
|
0
|
|
|
|
|
if ( $arg =~ m/^-/mxs ) { |
|
75
|
0
|
0
|
|
|
|
|
if ( exists $SWITCHES_WITH_PARAMETERS{$arg} ) { |
|
76
|
0
|
|
|
|
|
|
pop @files; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
0
|
|
|
|
|
|
last ARGUMENT; |
|
79
|
|
|
|
|
|
|
} |
|
80
|
0
|
|
|
|
|
|
push @files, $arg; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
|
|
83
|
0
|
|
|
|
|
|
my @other_args = @args[ 0 .. $#args - $#files - 1 ]; |
|
84
|
0
|
|
|
|
|
|
OTHER_ARGUMENT: for my $arg (@other_args) { |
|
85
|
0
|
0
|
|
|
|
|
if ( $arg =~ $IS_PROGRAM_SWITCH ) { |
|
86
|
0
|
|
|
|
|
|
$has_program_switch = 1; |
|
87
|
0
|
|
|
|
|
|
last OTHER_ARGUMENT; |
|
88
|
|
|
|
|
|
|
} |
|
89
|
|
|
|
|
|
|
} |
|
90
|
0
|
0
|
|
|
|
|
if ( !$has_program_switch ) { |
|
91
|
0
|
|
|
|
|
|
push @other_args, '-e', pop @files; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
0
|
|
|
|
|
|
return \@other_args, [ reverse @files ]; |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub get_variables { |
|
97
|
0
|
|
|
0
|
0
|
|
my ($files) = @_; |
|
98
|
|
|
|
|
|
|
|
|
99
|
0
|
|
|
|
|
|
my %results; |
|
100
|
0
|
|
|
|
|
|
my $csv = get_csv_parser(); |
|
101
|
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
for my $file ( @{$files} ) { |
|
|
0
|
|
|
|
|
|
|
|
103
|
0
|
|
|
|
|
|
open my $fh, '<', $file; |
|
104
|
0
|
|
|
|
|
|
my $headers = $csv->getline($fh); |
|
105
|
0
|
|
|
|
|
|
$results{$file} = [ map { convert_to_identifier($_) } @{$headers} ]; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
|
close $fh; |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
0
|
|
|
|
|
|
return \%results; |
|
110
|
|
|
|
|
|
|
} |
|
111
|
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
sub quote_files { |
|
113
|
0
|
|
|
0
|
0
|
|
my ($in_files) = @_; |
|
114
|
|
|
|
|
|
|
|
|
115
|
0
|
|
|
|
|
|
my %file_map; |
|
116
|
0
|
|
|
|
|
|
my $dir = tempdir(); |
|
117
|
0
|
|
|
|
|
|
my $csv = get_csv_parser(); |
|
118
|
|
|
|
|
|
|
|
|
119
|
0
|
|
|
|
|
|
for my $in_file ( @{$in_files} ) { |
|
|
0
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
|
my ( $out, $out_file ) = |
|
121
|
|
|
|
|
|
|
tempfile( basename($in_file) . '.XXXXXXXX', DIR => $dir ); |
|
122
|
0
|
|
|
|
|
|
$file_map{$in_file} = $out_file; |
|
123
|
0
|
|
|
|
|
|
open my $in, '<', $in_file; |
|
124
|
0
|
|
|
|
|
|
while ( my $row = $csv->getline($in) ) { |
|
125
|
0
|
|
|
|
|
|
for my $field ( @{$row} ) { |
|
|
0
|
|
|
|
|
|
|
|
126
|
0
|
|
|
|
|
|
$field = hide_separators($field); |
|
127
|
|
|
|
|
|
|
} |
|
128
|
0
|
|
|
|
|
|
$csv->print( $out, $row ); |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
0
|
|
|
|
|
|
close $in; |
|
132
|
0
|
|
|
|
|
|
close $out; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
return \%file_map; |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub build_library { |
|
139
|
0
|
|
|
0
|
0
|
|
my ( $files, $file_map, $variables ) = @_; |
|
140
|
0
|
|
|
|
|
|
my ( $fh, $filename ) = tempfile( SUFFIX => '.awk' ); |
|
141
|
|
|
|
|
|
|
|
|
142
|
0
|
|
|
|
|
|
print { *{$fh} } <<'END_AWK'; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
BEGIN { |
|
144
|
|
|
|
|
|
|
FS = "," |
|
145
|
|
|
|
|
|
|
OFS = "," |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
FNR == 1 { |
|
148
|
|
|
|
|
|
|
END_AWK |
|
149
|
|
|
|
|
|
|
|
|
150
|
0
|
|
|
|
|
|
for my $file ( @{$files} ) { |
|
|
0
|
|
|
|
|
|
|
|
151
|
0
|
|
|
|
|
|
my $tempfile = $file_map->{$file}; |
|
152
|
0
|
|
|
|
|
|
print { *{$fh} } qq( if (FILENAME == "$tempfile") {\n); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
153
|
0
|
|
|
|
|
|
my $i = 1; |
|
154
|
0
|
|
|
|
|
|
for my $variable ( @{ $variables->{$file} } ) { |
|
|
0
|
|
|
|
|
|
|
|
155
|
0
|
|
|
|
|
|
print { *{$fh} } " $variable = $i\n"; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
$i++; |
|
157
|
|
|
|
|
|
|
} |
|
158
|
0
|
|
|
|
|
|
print { *{$fh} } " }\n"; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
} |
|
160
|
0
|
|
|
|
|
|
print { *{$fh} } "}\n"; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
161
|
0
|
|
|
|
|
|
close $fh; |
|
162
|
|
|
|
|
|
|
|
|
163
|
0
|
|
|
|
|
|
return $filename; |
|
164
|
|
|
|
|
|
|
} |
|
165
|
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
sub csvawk { |
|
167
|
0
|
|
|
0
|
0
|
|
my (@args) = @_; |
|
168
|
0
|
|
|
|
|
|
my $dirname = dirname(__FILE__); |
|
169
|
0
|
|
|
|
|
|
my ( $other_args, $files ) = split_arguments(@args); |
|
170
|
0
|
|
|
|
|
|
my $file_map = quote_files($files); |
|
171
|
0
|
|
|
|
|
|
my $variables = get_variables($files); |
|
172
|
0
|
|
|
|
|
|
my $library = build_library( $files, $file_map, $variables ); |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
#<<< |
|
175
|
|
|
|
|
|
|
my @command = ( |
|
176
|
|
|
|
|
|
|
'awk', |
|
177
|
|
|
|
|
|
|
'-f', |
|
178
|
|
|
|
|
|
|
$library, |
|
179
|
0
|
|
|
|
|
|
@{$other_args}, |
|
180
|
0
|
|
|
|
|
|
map { $file_map->{$_} } @{$files}, |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
); |
|
182
|
|
|
|
|
|
|
#>>> |
|
183
|
|
|
|
|
|
|
|
|
184
|
0
|
|
|
|
|
|
open my $output, q(-|), @command; |
|
185
|
0
|
|
|
|
|
|
while ( my $row = <$output> ) { |
|
186
|
0
|
|
|
|
|
|
print restore_separators($row); |
|
187
|
|
|
|
|
|
|
} |
|
188
|
0
|
|
|
|
|
|
close $output; |
|
189
|
|
|
|
|
|
|
|
|
190
|
0
|
|
|
|
|
|
return 0; |
|
191
|
|
|
|
|
|
|
} |
|
192
|
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
1; |
|
194
|
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
__END__ |