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__ |