#! perl

use strict;
use warnings FATAL => 'all';
use v5.14;

use IO::File;

die "Usage: $0 <infile> <outfile>\n"
	unless @ARGV == 2;

my $cfg = new IO::File('config.perl', '<')
	or die "open(config.perl): $!\n";

my %invars = map { chomp; split /=/, $_, 2 } $cfg->getlines;

$cfg->eof or die "read(config.perl): $!\n";
$cfg->close;
undef $cfg;

my %outvars;

for(;;) {
	my $changed;
	while(my ($key, $val) = each %invars) {
		next unless $val =~ /^(?:[^\\\$\`]|\$(?:\{\w+}|\w+)|\\.)+$/a;
		$val =~ s{\\(.)|\$(?:\{(\w+)\}|(\w+))}{$1 // $outvars{$2 // $3} // ''}ega;
		next if exists $outvars{$key} && $val eq $outvars{$key};
		$outvars{$key} = $val;
		$changed = 1;
	}
	last unless $changed;
}

END { unlink("$ARGV[1].tmp.$$") }

my $out = new IO::File("$ARGV[1].tmp.$$", '>')
	or die "open($ARGV[0].tmp.$$): $!\n";

$out->write("#! $outvars{PERL}\n\nBEGIN {\n")
	or die "write($ARGV[1].tmp.$$): $!\n";

while(my ($key, $val) = each %outvars) {
	$val =~ s/[\\"\$\@]/\\$&/ga;
	$out->write("\tour \$$key = \"$val\";\n")
		or die "write($ARGV[1].tmp.$$): $!\n";
}

$out->write("}\n\n")
	or die "write($ARGV[1].tmp.$$): $!\n";

my $in = new IO::File($ARGV[0], '<')
	or die "open($ARGV[0]): $!\n";

my $pod;
while(<$in>) {
	$pod = 1 if /^=(\w+)(?:\s|$)/a;
	$out->write($_) or die "write($ARGV[1].tmp.$$): $!\n" unless $pod;
	$pod = 0 if /^=cut(?:\s|$)/a;
}

$in->eof or die "read($ARGV[0]): $!\n";
$in->close;
undef $in;

$out->flush or die "write($ARGV[1].tmp.$$): $!\n";
$out->sync or die "fsync($ARGV[1].tmp.$$): $!\n";
$out->close or die "close($ARGV[1].tmp.$$): $!\n";
undef $out;

chmod(0777 & ~umask, "$ARGV[1].tmp.$$")
	or die "chmod($ARGV[1].tmp.$$): $!\n";

rename("$ARGV[1].tmp.$$", $ARGV[1])
	or die "rename($ARGV[1].tmp.$$, $ARGV[1]): $!\n";
