#! /usr/bin/perl
# Written by Zack Weinberg <zackw at panix.com> in 2017.
# To the extent possible under law, Zack Weinberg has waived all
# copyright and related or neighboring rights to this work.
#
# See https://creativecommons.org/publicdomain/zero/1.0/ for further
# details.
# Generate (x)crypt.h from (x)crypt.h.in.
use v5.14; # implicit use strict, use feature ':5.14'
use warnings FATAL => 'all';
use utf8;
use open qw(:std :utf8);
no if $] >= 5.022, warnings => 'experimental::re_strict';
use if $] >= 5.022, re => 'strict';
use FindBin ();
use lib $FindBin::Bin;
use BuildCommon qw(
enabled_set
parse_hashes_conf
);
# Substitutions we know about are accumulated in this hash.
my %substs;
sub process_config_h {
my ($config_h) = @_;
open my $fh, '<', $config_h
or die "$config_h: $!\n";
my $have_sys_cdefs_h = 0;
my $have_sys_cdefs_begin_end_decls = 0;
my $have_sys_cdefs_throw = 0;
local $_;
while (<$fh>) {
chomp;
if ($_ eq '#define HAVE_SYS_CDEFS_H 1') {
$have_sys_cdefs_h = 1;
}
elsif ($_ eq '#define HAVE_SYS_CDEFS_BEGIN_END_DECLS 1') {
$have_sys_cdefs_begin_end_decls = 1;
}
elsif ($_ eq '#define HAVE_SYS_CDEFS_THROW 1') {
$have_sys_cdefs_throw = 1;
}
elsif (/^#define PACKAGE_VERSION "((\d+)\.(\d+)\.\d+)"$/) {
$substs{XCRYPT_VERSION_STR} = $1;
$substs{XCRYPT_VERSION_MAJOR} = $2;
$substs{XCRYPT_VERSION_MINOR} = $3;
}
}
die "$config_h: error: inconsistent <sys/cdefs.h> settings\n"
if !$have_sys_cdefs_h
&& ($have_sys_cdefs_begin_end_decls || $have_sys_cdefs_throw);
my $s = q{};
my $e = q{};
$s .= "#include <sys/cdefs.h>\n" if $have_sys_cdefs_h;
$s .= "#define __THROW /* nothing */\n" unless $have_sys_cdefs_throw;
$s .= "\n";
if ($have_sys_cdefs_begin_end_decls) {
$s .= '__BEGIN_DECLS';
$e .= '__END_DECLS';
} else {
$s .= "#ifdef __cplusplus\nextern \"C\" {\n#endif";
$e .= "#ifdef __cplusplus\n} /* extern \"C\" */\n#endif";
}
$substs{BEGIN_DECLS} = $s;
$substs{END_DECLS} = $e;
return;
}
sub process_hashes_conf {
my ($hashes_conf, $hashes_enabled) = @_;
my %enabled = enabled_set($hashes_enabled);
my $hconf = parse_hashes_conf($hashes_conf);
my $default_prefix_enabled = 0;
for my $e (@{$hconf->default_candidates}) {
if ($enabled{$e->name}) {
$default_prefix_enabled = 1;
last;
}
}
$substs{DEFAULT_PREFIX_ENABLED} = $default_prefix_enabled;
return;
}
sub substitute {
my ($infile) = @_;
open my $fh, '<', $infile
or die "$infile: $!\n";
my $error = 0;
local $_;
my $subst1 = sub {
my $rep = $substs{$_[0]};
return $rep if defined $rep;
print {*STDERR} "$infile:$.: error: no substitution for $_[0]\n";
$error = 1;
return "!$_[0]!";
};
while (<$fh>) {
s/@([A-Z0-9_]+)@/&$subst1($1)/eg;
print;
}
exit 1 if $error;
return;
}
#
# Main
#
if (scalar(@ARGV) != 2 && scalar(@ARGV) != 4) {
print {*STDERR} 'usage: '
. ${FindBin::Script}
. ' template config.h [hashes.conf ,hashes,enabled,]' . "\n";
exit 1;
}
exit 0 if eval {
my $infile = shift @ARGV;
process_config_h(shift @ARGV);
process_hashes_conf(@ARGV) if @ARGV;
substitute($infile);
close STDOUT or die "write error: $!\n";
1;
};
print {*STDERR} "${FindBin::Script}: $@";
exit 1;