Periods (.) in extension patterns are now allowed (for things like .tar.gz)
[conv.git] / conv.pl
1 #!/usr/bin/perl
2 use Getopt::Std;
3 use File::Basename;
4 use strict;
5 use warnings;
6
7 my %rules;
8 my %vars;
9 my %opts = (
10     j => 1
11 );
12
13 getopts('vnj:f:o:s:', \%opts);
14
15 print "Using $opts{j} processors\n" if $opts{v};
16
17 my $var_re = qr/[A-Za-z_][A-Za-z0-9_]*/;
18
19 sub convert {
20     my ($base, $iext, $oext) = @_;
21     my $cmd = $rules{$oext}{$iext};
22     my $infile = "$base.$iext";
23     $infile =~ s/"/\\"/g;
24     $cmd =~ s!\$\<!"$infile"!g;
25     my $outfile;
26     if ($opts{o}) {
27         # Strip leading path from base so we can stick the file in
28         # another dir.
29         $base = basename($base);
30         $outfile = "$opts{o}/$base.$oext";
31     } else {
32         $outfile = "$base.$oext";
33     }
34     $outfile =~ s/"/\\"/g;
35     $cmd =~ s!\$\@!"$outfile"!g;
36     $cmd = expand($cmd);
37     print "$cmd\n";
38     return if $opts{n};
39     my $pid = fork();
40     return $pid if $pid;
41
42     exec($cmd);
43 }
44
45 sub expand {
46     local $_ = shift;
47     s/\$($var_re)/(exists $vars{$1} ? $vars{$1} : '$' . $1)/eg;
48     return $_;
49 }
50
51 open CONF, ($opts{f} || 'Convfile') or die "Could not open Convfile";
52 while (<CONF>) {
53     s/#.*$//;
54     s/^\s+//;
55     s/\s+$//;
56     next if /^$/;
57
58     if (/^([\w.]+)\s*=>\s*([\w.]+)\s*:\s*(.*)$/) {
59         $rules{$2}{$1} = $3;
60     } elsif (/^($var_re)\s*=\s*(.*)$/) {
61         $vars{$1} = expand($2);
62     } else {
63         warn "Error in Convfile line $.: $_\n";
64     }
65 }
66 close CONF;
67
68 my @queue;
69
70 # If we specify reading from stdin, do this.
71 if (exists $opts{s}) {
72     while (<STDIN>) {
73         next if /^#/;
74         chomp;
75         
76         unless (-e $_) {
77             print "File specified on stdin, $_, does not exist.\n";
78             next;
79         }
80
81         if (/^(.+)\.(\w+)$/) {
82             my $base = $1;
83             my $iext = $2;
84             print "Considering $base.$iext\n" if $opts{v};
85             if (exists $rules{$opts{s}}{$iext}) {
86                 print "Using $base.$iext\n" if $opts{v};
87                 push @queue, [$base, $iext, $opts{s}];
88             }
89         } else {
90             print "I don't see an extension on $_, so I don't know what to do with it.\n";
91         }
92     }
93 }
94
95 # Not reading filenames from stdin.
96 else {
97     # Do something fun
98     my @tmpARGV;
99     foreach (@ARGV) {
100         if (/^\*\.(\w+)$/) {
101             my $extsub = $1;
102             opendir D, '.';
103             my @files = 
104             map { s/\.(\w+)$/\.$extsub/; $_ } 
105                 grep { /^[^.]/ }
106                 readdir D;
107             closedir D;
108             push @tmpARGV, @files;
109         } else {
110             push @tmpARGV, $_;
111         }
112     }
113     @ARGV = @tmpARGV;
114     
115     # I like to call this the TOWER OF POWER
116     for my $ofile (@ARGV) {
117         my $ofound = 0;
118         for my $oext (keys %rules) {
119             my $oext_re = $oext;
120             $oext_re =~ s/\./\\./g;
121             if ($ofile =~ /^(.*)\.$oext_re$/) {
122                 my $base = $1;
123                 my $ifound = 0;
124                 for my $iext (keys %{$rules{$oext}}) {
125                     print "Considering $base.$iext\n" if $opts{v};
126                     if (-e "$base.$iext") {
127                         print "Using $base.$iext\n" if $opts{v};
128                         push @queue, [$base, $iext, $oext];
129                         $ifound = 1;
130                         last;
131                     }
132                 }
133                 unless ($ifound) {
134                     print "No suitable input file found for $ofile\n";
135                 }
136                 $ofound = 1;
137                 last;
138             }
139         }
140         unless ($ofound) {
141             print "No rule to make $ofile\n";
142         }
143     }
144 }
145
146 print scalar @queue, " items to process\n" if $opts{v};
147
148 my $procs = 0;
149 foreach my $chunk (@queue) {
150     convert(@$chunk);
151     $procs++;
152     if ($procs == $opts{j}) {
153         wait;
154         $procs--;
155     }
156 }
157 wait while $procs--;
158
159 # vim:set ts=4 sts=4 sw=4 expandtab: