#! /usr/bin/perl -w
use diagnostics;
use strict;
use Getopt::Long;

sub usage ()
{
    print STDERR <<"EOF";
Usage: $0 [options] source-filename
EOF
    print STDERR <<'EOF';
where options are:

  -h, -?, --help            print this message
  -c,     --conf FILENAME   use FILENAME as configuration file, default
                            '.headers'
  -d,     --directory DIR   change to directory DIR
  -s,     --suffix SUFFIX   use SUFFIX for all output filenames, default null

The configuration file is of the following form:

# Comments are preceded by hashes and extend to the end of the line.
# List of names of parameters to be substituted (as $param1$, $param2$,
# etc.) in order.
param1 param2 ...

# Multiple records, one per line.
# Each record consists of an output filename (automatically used as the value
# of the name parameter; suffix will be added if present) followed by a list of
# parameter values. Fields are space-separated. Double quotes (") may be used
# to delimit fields containing spaces, and double quotes themselves may be
# escaped with backslashes.

EOF
    exit;
}

my %opts = (conf => '.headers', directory => '', suffix => '');
GetOptions(\%opts, 'help|h|?', 'conf|c=s', 'directory|d=s', 'suffix|s=s');
my $source = shift;
usage unless defined $source;

usage if $opts{'help'};
chdir $opts{'directory'} if $opts{'directory'};
open CONF, $opts{'conf'} or
    die "Can't open configuration file " . $opts{'conf'} . ": $!";
-r $source or die "Can't read source file $source: $!";

my @params;
while (<CONF>)
{
    next if /^#/ || /^\s+/;
    @params = split;
    last;
}

usage unless defined @params && $#params >= 0;

# Eek. This matches the next (optionally double-quoted) string on the line.
my $stringre = qr/\s*("(?:[^\\]|\\.)*?"|(?:[^\\]|\\.)+?)(?:\s|$)/;
while (<CONF>)
{
    next if /^#/ || /^\s+/;
    my $confline = $_;
    next unless $confline =~ /$stringre/g;
    my $target = $1;
    my %values = (name => $target);
    my @conffields = ($confline =~ /\G$stringre/g);
    my $offset = 0;
    for (my $i = 0; $i + $offset <= $#params && $i <= $#conffields; $i++)
    {
	$offset++ while $params[$i + $offset] eq 'name';
	last if $i + $offset > $#params;
	my $value = $conffields[$i];
	$value =~ s/^"(.*)"$/$1/;
	$value =~ s/\\(.)/$1/g;
	$values{$params[$i + $offset]} = $value;
    }

    # Do the substitution in the source file.
    open SOURCE, $source or die "Can't open source file $source: $!";
    open TARGET, ">$target" . $opts{'suffix'} or
	die "Can't open target file $target" . $opts{'suffix'} . ": $!";
    select TARGET;
    while (<SOURCE>)
    {
	foreach my $param (keys %values)
	{
	    my $value = $values{$param};
	    s/\$\Q$param\E\$/$value/g;
	}
	s/\$\$/\$/g;
	print;
    }
    select STDOUT;
    close TARGET;
}

