#!/usr/bin/env perl
use Getopt::Long;
$Getopt::Long::autoabbrev = 1;
$Getopt::Long::ignorecase = 0;
use File::Basename;
use strict;
# Defaults + Variables
my $dmaxchannel = 64
my $maxchannel = -1;
my $dbytes = 3;
my $bytes = -1;
my $dreadinc = 500;
my $readinc = -1;
my $channel = -1;
my $infile = "";
my $outfile = "";
my $force = 0;
my $quiet = 0;
my $use1of = 0;
# Usage
my $usage =<< "END";
Usage: $0 [--outfile F] [--channels C] [--bytes B] [--readinc R] [--fo
+rce] [--quiet] channelnumber inputfile [inputfile inputfile ...]
channelnumber channel to extract
inputfile file to open (raw data)
--outfile F file to write the extracted channel to (default is "
+channelnumber-inputfile"). Only one file can be specified, all data f
+rom input files will be concatenated to this file.
--channels C number of channels in the input file (default: $dmax
+channel)
--bytes B number of bytes per channel in the input file (defau
+lt: $dbytes)
--readinc R Number of chunks of data to process at a time (for s
+peedup vs memory use) (default: $dreadinc)
--force Forces the use of input file if its size does not ma
+tch the 'channels*bytes' requirements
--quiet Run in quiet mode
END
# Option processing + use of default values
GetOptions
(
'outfile=s' => \$outfile,
'channels=i' => \$maxchannel,
'bytes=i' => \$bytes,
'readinc=i' => \$readinc,
'force' => sub {$force = 1;},
'quiet' => sub {$quiet = 1;}
) || usage();
$maxchannel = $dmaxchannel if ($maxchannel == -1);
$bytes = $dbytes if ($bytes == -1);
$readinc = $dreadinc if ($readinc == -1);
my $verb = ($quiet == 1) ? 0 : 1;
$use1of = ($outfile ne "") ? 1 : 0;
$| = 1 if ($verb);
# Channel number
$channel = shift @ARGV;
die "Error: Channel ($channel) must be between 1 and $maxchannel\n\n$u
+sage"
if (($channel < 1) || ($channel > $maxchannel));
####################
# Opening/Checking Input file
my @tinfiles = @ARGV;
my @infiles;
my $tfs = 0;
my %fs;
print "\nChecking input file(s)..." if ($verb);
foreach $infile (@tinfiles) {
die "Error: Invalid file name ($infile)\n"
if ($infile eq "");
$infile =~ s{^~([^/]*)}{$1?(getpwnam($1))[7]:($ENV{HOME} || $ENV{LOG
+DIR})}ex;
push @infiles, $infile;
if (exists $fs{$infile}) {
print "Warning: file ($infile) seems to be listed more than once\n
+";
next;
}
die "Error: Input file ($infile) does not exist, aborting !\n"
if (! -e $infile);
$fs{$infile} = (stat($infile))[7];
$tfs += $fs{$infile};
die "Error: Input file size (" . $fs{$infile} . ") is not a multiple
+ of $maxchannel channels by $bytes bytes (maybe not a \"real\" raw fi
+le); use \'--force\' to process this file\n"
if ((! $force) && ($fs{$infile} % ($maxchannel * $bytes)));
open INFILE, "<$infile"
or die "Error: Could not open input file ($infile): $!\n\n$usage";
close INFILE;
}
print " done\n" if ($verb);
####################
# Processing each input files
my $totalread;
my $percent;
my ($tottofs, $totwofs);
while ($infile = shift @infiles) { # "foreach" does not seem to set $i
+nfile
### Creating outputfile
# Multiple output files
if ($use1of == 0) {
if ($outfile eq "") {
$outfile = $infile;
$outfile =~ /^(.*?)([^\/]+)$/;
my $infile_dir = $1;
my $infile_file = $2 ;
$outfile = $infile_dir . sprintf("%02d", $channel) . "-$infile_f
+ile";
}
}
# Multiple and single output file
if (($use1of - 1) <= 0) {
$outfile =~ s{^~([^/]*)}{$1?(getpwnam($1))[7]:($ENV{HOME} || $ENV{
+LOGDIR})}ex;
my $as = checkspaceleft($outfile);
my $sr = (($use1of == 1) ? $tfs : $fs{$infile}) / $maxchannel;
my $ksr = $sr / 1024; # kb value (for 'df -k')
die "Error: Not enough space left on device for writting output fi
+le ($outfile), estimated size of $ksr KB is more than available ($as
+KB), aborting\n" if ($as < $ksr);
open OUTFILE, ">$outfile"
or die "Error: Could not open output file ($outfile): $!\n\n$usa
+ge";
binmode OUTFILE;
}
# One output file ... stay with only one
$use1of++ if ($use1of == 1);
### Opening inputfile
open INFILE, "<$infile"
or die "Error: Could not open input file ($infile): $!\n\n$usage";
binmode INFILE;
if ($verb) {
print "\n";
print << "END";
Will extract:
- Channel $channel (out of $maxchannel) with $bytes byte(s) per chann
+el
- Input file : $infile
- Output file: $outfile
- will read/write a group of $readinc such elements at a time (for sp
+eedup)
END
print "\n";
}
my $toread = $readinc*$maxchannel*$bytes;
my $toskip_pre = $bytes*($channel - 1);
my $toskip_post = ($maxchannel - $channel)*$bytes;
my $running = 1;
my $read = 0;
my $outsize = 0;
my $buffer;
$percent = -1; # Set the variable even if we do not use it
$totalread = 0;
while ($running) {
$read = read(INFILE, $buffer, $toread);
$totalread += $read;
$running = 0 if ($read < $toread);
my $outbuffer = "";
for (my $i = 0; $i < $read; $i += $maxchannel*$bytes) {
my $done = ($buffer =~ s/^.{$toskip_pre}(.{$bytes}).{$toskip_pos
+t}//s);
if ($done) {
$outbuffer .= $1;
$outsize += $bytes;
}
}
print OUTFILE $outbuffer;
pprint();
}
if (! $quiet) {
print "\rProgress ... done \n\n";
print "Read from input file : ", $totalread, " bytes\n";
print "Supposed output file size: ", $totalread / $maxchannel, " b
+ytes\n";
print "Written to output file : ", $outsize, " bytes\n";
}
if ($use1of == 2) {
$tottofs += $totalread / $maxchannel;
$totwofs += $outsize;
}
close INFILE;
close OUTFILE if ($use1of == 0);
}
if ($use1of == 2) {
close OUTFILE;
if ($verb) {
print "\n";
print "Total supposed output file size : ", $tottofs, " bytes\n";
print "Total written output file size : ", $totwofs, " bytes\n";
print "Real output file size : ", (stat($outfile))[7], "
+ bytes\n";
}
}
sub checkspaceleft {
my $file = shift @ARGV;
my $return = 10000;
my $match = "";
my $base = dirname($file);
$base = $ENV{PWD} if ($base eq ".");
my @tmp = 'df -k';
chomp(@tmp);
shift(@tmp);
foreach my $line (@tmp) {
my ($dev, $blocks, $used, $avail, $cap, $mount) = split(/\s+/, $li
+ne);
next if ($base !~ /^$mount/);
if (length($match) < length($mount)) {
$match = $mount;
$return = $blocks;
}
}
return $return;
}
sub pprint {
return if ($quiet);
my $t = int (100 * $totalread / $fs{$infile});
if ($t > $percent) {
printf("\rProgress: %03d %%", $t);
$percent = $t;
}
}
|