/conv.pl
use Getopt::Std;
use File::Basename;
use strict;
use warnings;
my %rules;
my %vars;
my %opts = (
j => 1
);
getopts('vnsj:f:o:i:', \%opts);
my $dirout;
if (defined $opts{ }) {
if (-d $opts{ }) {
# output is a directory
$dirout = 1;
} else {
# output is a single file, imply -i <ext> unless -i has also been specified
if ($opts{ } =~ /\.(\w+)$/) {
$opts{ } = $1 unless exists $opts{ };
} else {
print "Specified -o <file>, but '$opts{o}' has no extension.\n";
exit 1;
}
}
}
print "Using $opts{j} processors\n" if $opts{ };
my $var_re = qr/[A-Za-z_][A-Za-z0-9_]*/;
{
my ($base, $iext, $oext) = @_;
my $cmd = $rules{$oext}{$iext};
my $infile = "$base.$iext";
$infile =~ s/"/\\"/g;
$cmd =~ s!\$\<!"$infile"!g;
$cmd =~ s!\$\*!"$base"!g;
my $outfile;
if ($opts{ }) {
if ($dirout) {
# Strip leading path from base so we can stick the file in
# another dir.
$base = basename($base);
$outfile = "$opts{o}/$base.$oext";
} else {
$outfile = $opts{ };
}
} else {
$outfile = "$base.$oext";
}
$outfile =~ s/"/\\"/g;
$cmd =~ s!\$\@!"$outfile"!g;
$cmd = expand($cmd);
print "$cmd\n";
return if $opts{ };
my $pid = fork();
return $pid if $pid;
exec($cmd);
}
{
local $_ = shift;
s/\$($var_re)/(exists $vars{$1} ? $vars{$1} : '$' . $1)/eg;
return $_;
}
open CONF, ($opts{ } || 'Convfile') or die "Could not open Convfile";
while (<CONF>) {
s/#.*$//;
s/^\s+//;
s/\s+$//;
next if /^$/;
if (/^([\w.-]+)\s*=>\s*([\w.-]+)\s*:\s*(.*)$/) {
$rules{$2}{$1} = $3;
} elsif (/^($var_re)\s*=\s*(.*)$/) {
$vars{$1} = expand($2);
} else {
warn "Error in Convfile line $.: $_\n";
}
}
close CONF;
my @queue;
my @files;
if (exists $opts{s}) {
while (<STDIN>) {
next if /^#/;
chomp;
push @files, $_;
}
} else {
@files = @ARGV;
}
if ($opts{ }) {
unless (exists $rules{$opts{ }}) {
print <<EOD;
You have specified -i <ext>, but the Convfile has no rule to convert to
extension '$opts{i}'
EOD
exit 1;
}
foreach (@files) {
unless (-e $_) {
print "$_ does not exist.\n";
next;
}
if (/^(.+)\.(\w+)$/) {
my $base = $1;
my $iext = $2;
print "Considering $base.$iext\n" if $opts{ };
if (exists $rules{$opts{ }}{$iext}) {
print "Using $base.$iext\n" if $opts{ };
push @queue, [$base, $iext, $opts{ }];
}
} else {
print "I don't see an extension on $_, so I don't know what to do with it.\n";
}
}
}
else {
# Do something fun (convert *.foo into a list of files that would match if they existed)
my @tmpfiles;
foreach (@files) {
if (/^\*\.(\w+)$/) {
my $extsub = $1;
push @tmpfiles,
map { s/\.(\w+)$/\.$extsub/; $_ }
grep { /^[^.]/ }
<*>;
} else {
push @tmpfiles, $_;
}
}
@files = @tmpfiles;
# I like to call this the TOWER OF POWER
for my $ofile (@files) {
my $ofound = 0;
for my $oext (keys %rules) {
my $oext_re = $oext;
$oext_re =~ s/\./\\./g;
if ($ofile =~ /^(.*)\.$oext_re$/) {
my $base = $1;
my $ifound = 0;
for my $iext (keys %{$rules{$oext}}) {
print "Considering $base.$iext\n" if $opts{ };
if (-e "$base.$iext") {
print "Using $base.$iext\n" if $opts{ };
push @queue, [$base, $iext, $oext];
$ifound = 1;
last;
}
}
unless ($ifound) {
print "No suitable input file found for $ofile\n";
}
$ofound = 1;
last;
}
}
unless ($ofound) {
print "No rule to make $ofile\n";
}
}
}
print scalar @queue, " items to process\n" if $opts{ };
my $procs = 0;
foreach my $chunk (@queue) {
convert(@$chunk);
$procs++;
if ($procs == $opts{ }) {
wait;
$procs--;
}
}
wait while $procs--;