|
Packit Service |
c5cf8c |
#! @PERL@
|
|
Packit Service |
c5cf8c |
# -*- Mode: Perl; -*-
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
# (C) 2004 by Argonne National Laboratory.
|
|
Packit Service |
c5cf8c |
# See COPYRIGHT in top-level directory.
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
# This file provides a way to merge a template file with a set of
|
|
Packit Service |
c5cf8c |
# code fragments. This makes it simple to generate many related tests
|
|
Packit Service |
c5cf8c |
# from a single test harness, while ending up with relatively simple code
|
|
Packit Service |
c5cf8c |
# in case it is necessary to debug the code.
|
|
Packit Service |
c5cf8c |
# The template file uses an XML-like notation to mark off places for code.
|
|
Packit Service |
c5cf8c |
# Specifically, lines of the form
|
|
Packit Service |
c5cf8c |
# <name/>
|
|
Packit Service |
c5cf8c |
# are replaced from a definition file. The template is XML-like because
|
|
Packit Service |
c5cf8c |
# angle brackets and ampersands can be freely used as long as they don't
|
|
Packit Service |
c5cf8c |
# match the perl pattern <\w*\/> (which no valid C, C++, or Fortran code will)
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
# The file of definitions has the following form, also in an XML-like
|
|
Packit Service |
c5cf8c |
# format (for simple parsing)
|
|
Packit Service |
c5cf8c |
# <TESTDEFN filename="fname">
|
|
Packit Service |
c5cf8c |
# <blockname>
|
|
Packit Service |
c5cf8c |
# definition
|
|
Packit Service |
c5cf8c |
# </blockname>
|
|
Packit Service |
c5cf8c |
# ...
|
|
Packit Service |
c5cf8c |
# </TESTDEFN>
|
|
Packit Service |
c5cf8c |
# where "blockname" is an arbitrary name (matching the perl expression \w*)
|
|
Packit Service |
c5cf8c |
# that matches the names in the template file.
|
|
Packit Service |
c5cf8c |
# TESTDEFN is a required field
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
# Possible extensions:
|
|
Packit Service |
c5cf8c |
# Common definitions for all files (allows a common template for
|
|
Packit Service |
c5cf8c |
# multiple sets of merges)
|
|
Packit Service |
c5cf8c |
# Allow the *template* to define some names (eg, value)
|
|
Packit Service |
c5cf8c |
# that are replaced in the generated file.
|
|
Packit Service |
c5cf8c |
#
|
|
Packit Service |
c5cf8c |
# ----------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# Global variables
|
|
Packit Service |
c5cf8c |
$debug = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
$lang = "Fortran";
|
|
Packit Service |
c5cf8c |
%knownLang = ( "Fortran" => 1, "C" => 1, "C++" => 1 );
|
|
Packit Service |
c5cf8c |
#$lang = "C";
|
|
Packit Service |
c5cf8c |
#$lang = "C++";
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
# Definitions
|
|
Packit Service |
c5cf8c |
%Definitions = ();
|
|
Packit Service |
c5cf8c |
# Global definitions are for all files, and can contain standard comments,
|
|
Packit Service |
c5cf8c |
# initializations, and other data
|
|
Packit Service |
c5cf8c |
%GlobalDefinitions = ();
|
|
Packit Service |
c5cf8c |
# Read a definition file
|
|
Packit Service |
c5cf8c |
# ReadDefinition( filename )
|
|
Packit Service |
c5cf8c |
# Places the definitions into %Definitions{name} => content
|
|
Packit Service |
c5cf8c |
sub ReadDefinition {
|
|
Packit Service |
c5cf8c |
my $DFD = $_[0];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
while (<$DFD>) {
|
|
Packit Service |
c5cf8c |
# Check for end-of-description
|
|
Packit Service |
c5cf8c |
if (/<\/TESTDEFN>/) { last; }
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
# match definition name
|
|
Packit Service |
c5cf8c |
if (/<(\w*)>/) {
|
|
Packit Service |
c5cf8c |
my $name = $1;
|
|
Packit Service |
c5cf8c |
my $defn = "";
|
|
Packit Service |
c5cf8c |
my $found = 0;
|
|
Packit Service |
c5cf8c |
while (<$DFD>) {
|
|
Packit Service |
c5cf8c |
if (/<\/$name>/) { $found = 1; last; }
|
|
Packit Service |
c5cf8c |
s/\r//g; # Remove any extraneous characters
|
|
Packit Service |
c5cf8c |
$defn .= $_;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
# If we didn't close the definition, generate an error message
|
|
Packit Service |
c5cf8c |
if (! $found) {
|
|
Packit Service |
c5cf8c |
print STDERR "Read to end-of-file while looking for </$name>\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
$Definitions{$name} = $defn;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
else {
|
|
Packit Service |
c5cf8c |
# Skip (blank space, comment, etc)
|
|
Packit Service |
c5cf8c |
next;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
# ReadGlobalDefinitions( filename )
|
|
Packit Service |
c5cf8c |
sub ReadGlobalDefinitions {
|
|
Packit Service |
c5cf8c |
my $filename = $_[0];
|
|
Packit Service |
c5cf8c |
# Save Definitions, if any
|
|
Packit Service |
c5cf8c |
my %saveDefinitions = %Definitions;
|
|
Packit Service |
c5cf8c |
# Reset Definitions to hold the current global set
|
|
Packit Service |
c5cf8c |
%Definitions = %GlobalDefinitions;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
my $DFD = "DFD";
|
|
Packit Service |
c5cf8c |
open $DFD, "<$filename" || die "Could not open global definition file $filename\n";
|
|
Packit Service |
c5cf8c |
print "Opening $filename..\n";
|
|
Packit Service |
c5cf8c |
&ReadDefinition( $DFD );
|
|
Packit Service |
c5cf8c |
close $DFD;
|
|
Packit Service |
c5cf8c |
%GlobalDefinitions = %Definitions;
|
|
Packit Service |
c5cf8c |
%Definitions = %saveDefinitions;
|
|
Packit Service |
c5cf8c |
# Print the new definitions if requested.
|
|
Packit Service |
c5cf8c |
if ($debug) {
|
|
Packit Service |
c5cf8c |
foreach my $key (keys(%GlobalDefinitions)) {
|
|
Packit Service |
c5cf8c |
my $val = $GlobalDefinitions{$key};
|
|
Packit Service |
c5cf8c |
print "$key => $val\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
# ---------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# MergeTemplate
|
|
Packit Service |
c5cf8c |
# Read a template and merge the output
|
|
Packit Service |
c5cf8c |
# MergeTemplate( template file, output file )
|
|
Packit Service |
c5cf8c |
# Preserve indentation
|
|
Packit Service |
c5cf8c |
sub MergeTemplate {
|
|
Packit Service |
c5cf8c |
my $templateFilename = $_[0];
|
|
Packit Service |
c5cf8c |
my $outputFilename = $_[1];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
open IFD, "<$templateFilename" || die "Cannot open $templateFilename\n";
|
|
Packit Service |
c5cf8c |
open OFD, ">$outputFilename" || die "Cannot open $outputFilename\n";
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
while (<IFD>) {
|
|
Packit Service |
c5cf8c |
s/\r//;
|
|
Packit Service |
c5cf8c |
my $loopLimit = 20;
|
|
Packit Service |
c5cf8c |
while (/(\s*)<(\w*)\/>/) {
|
|
Packit Service |
c5cf8c |
my $indent = $1;
|
|
Packit Service |
c5cf8c |
my $name = $2;
|
|
Packit Service |
c5cf8c |
$indent =~ s/\s*\n//g;
|
|
Packit Service |
c5cf8c |
if ($loopLimit-- <= 0) {
|
|
Packit Service |
c5cf8c |
print STDERR "Exceeded loop limit while writing $outputFilename\n";
|
|
Packit Service |
c5cf8c |
print STDERR "Searching for $name in $_";
|
|
Packit Service |
c5cf8c |
last;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (defined($Definitions{$name})) {
|
|
Packit Service |
c5cf8c |
my $defn = $Definitions{$name};
|
|
Packit Service |
c5cf8c |
my $newdefn = "";
|
|
Packit Service |
c5cf8c |
# Add indentation to definition; substitute any defintions
|
|
Packit Service |
c5cf8c |
foreach my $line (split(/\n/,$defn)) {
|
|
Packit Service |
c5cf8c |
print "Looking at |$line|\n" if $debug;
|
|
Packit Service |
c5cf8c |
$newdefn .= $indent . $line . "\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
chop $newdefn;
|
|
Packit Service |
c5cf8c |
print "Replacing <$name> with |$newdefn|\n" if $debug;
|
|
Packit Service |
c5cf8c |
s/$indent<$name\/>/$newdefn/; # Only do one at a time
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif (defined($GlobalDefinitions{$name})) {
|
|
Packit Service |
c5cf8c |
# local definitions can override any global definitions
|
|
Packit Service |
c5cf8c |
my $defn = $GlobalDefinitions{$name};
|
|
Packit Service |
c5cf8c |
my $newdefn = "";
|
|
Packit Service |
c5cf8c |
# Add indentation to definition
|
|
Packit Service |
c5cf8c |
foreach my $line (split(/\n/,$defn)) {
|
|
Packit Service |
c5cf8c |
$newdefn .= $indent . $line . "\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
print "Replacing <$name> with |$newdefn|\n" if $debug;
|
|
Packit Service |
c5cf8c |
chop $newdefn;
|
|
Packit Service |
c5cf8c |
s/$indent<$name\/>/$newdefn/; # Only do one at a time
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
else {
|
|
Packit Service |
c5cf8c |
# Unknown name!
|
|
Packit Service |
c5cf8c |
print STDERR "Unknown name $name in template file when creating $outputFilename!\n";
|
|
Packit Service |
c5cf8c |
last;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
&printLine( OFD, $_ );
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
close OFD;
|
|
Packit Service |
c5cf8c |
close IFD;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
# ---------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# ReadAndMerge( description file, template file )
|
|
Packit Service |
c5cf8c |
sub ReadAndMerge {
|
|
Packit Service |
c5cf8c |
my $filename = $_[0];
|
|
Packit Service |
c5cf8c |
my $templateFile = $_[1];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
$DFD = "DFD";
|
|
Packit Service |
c5cf8c |
open $DFD, "<$filename" || die "Can not open $filename\n";
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
while (<$DFD>) {
|
|
Packit Service |
c5cf8c |
s/#.*//; # Remove comments
|
|
Packit Service |
c5cf8c |
# Read until a TESTDEFN line
|
|
Packit Service |
c5cf8c |
if (/<TESTDEFN\s+filename=\"(.*)\">/) {
|
|
Packit Service |
c5cf8c |
my $outputFile = $1;
|
|
Packit Service |
c5cf8c |
%Definitions = ();
|
|
Packit Service |
c5cf8c |
# Read until </TESTDEFN>
|
|
Packit Service |
c5cf8c |
&ReadDefinition( $DFD );
|
|
Packit Service |
c5cf8c |
# Create the merged file
|
|
Packit Service |
c5cf8c |
&MergeTemplate( $templateFile, $outputFile );
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif (/<LANG>([\w\+]*)<\/LANG>/) {
|
|
Packit Service |
c5cf8c |
# Special for language definition
|
|
Packit Service |
c5cf8c |
$lang = $1;
|
|
Packit Service |
c5cf8c |
if (!defined($knownLang{$lang})) {
|
|
Packit Service |
c5cf8c |
print STDERR "Unknown language $lang\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif (/<(\w*)>/) {
|
|
Packit Service |
c5cf8c |
my $name = $1;
|
|
Packit Service |
c5cf8c |
my $defn = "";
|
|
Packit Service |
c5cf8c |
# read this as a global definition
|
|
Packit Service |
c5cf8c |
while (<$DFD>) {
|
|
Packit Service |
c5cf8c |
if (/<\/$name>/) { last; }
|
|
Packit Service |
c5cf8c |
s/\r//;
|
|
Packit Service |
c5cf8c |
$defn .= $_;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
if (eof($DFD)) { print STDERR "found EOF before end of $name\n"; }
|
|
Packit Service |
c5cf8c |
$GlobalDefinitions{$name} = $defn;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
close $DFD;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
# --------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# Debug
|
|
Packit Service |
c5cf8c |
sub PrintDefinitions {
|
|
Packit Service |
c5cf8c |
foreach my $name (keys(%Definitions)) {
|
|
Packit Service |
c5cf8c |
print "<$name>\n";
|
|
Packit Service |
c5cf8c |
my $defn = $Definitions{$name};
|
|
Packit Service |
c5cf8c |
# Here we could consider doing replacement for embedded <name>...</name>,
|
|
Packit Service |
c5cf8c |
# for things like arguments.
|
|
Packit Service |
c5cf8c |
print $defn;
|
|
Packit Service |
c5cf8c |
print "</$name>\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
# --------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# printLine handles any continuation conventions
|
|
Packit Service |
c5cf8c |
# printLine ( FD, lines )
|
|
Packit Service |
c5cf8c |
# Note that a very simple approach works for Fortran because blanks
|
|
Packit Service |
c5cf8c |
# are ignored. However, we will try to make the code easier to read
|
|
Packit Service |
c5cf8c |
sub printLine {
|
|
Packit Service |
c5cf8c |
my $OFD = $_[0];
|
|
Packit Service |
c5cf8c |
my $lines = $_[1];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
# Make sure that we get the current conventions
|
|
Packit Service |
c5cf8c |
if ($lang eq "Fortran") {
|
|
Packit Service |
c5cf8c |
$maxPrintLine = 72;
|
|
Packit Service |
c5cf8c |
$postLine = " &";
|
|
Packit Service |
c5cf8c |
$preLine = " &";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif ($lang eq "C" || $lang eq "C++") {
|
|
Packit Service |
c5cf8c |
$maxPrintLine = 180;
|
|
Packit Service |
c5cf8c |
$postLine = "";
|
|
Packit Service |
c5cf8c |
$preLine = "\t";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
foreach my $line (split(/\n/,$lines)) {
|
|
Packit Service |
c5cf8c |
# Compute length
|
|
Packit Service |
c5cf8c |
my $length = length($line);
|
|
Packit Service |
c5cf8c |
while ($length > $maxPrintLine) {
|
|
Packit Service |
c5cf8c |
# For Fortran 90 and C/C++, lines must be
|
|
Packit Service |
c5cf8c |
# broken at whitespace. Fortran 77 ignores whitespace,
|
|
Packit Service |
c5cf8c |
my $subline = substr $line, 0, $maxPrintLine;
|
|
Packit Service |
c5cf8c |
# Now, break subline at the last non-letter
|
|
Packit Service |
c5cf8c |
if ($subline =~ /(.*)([^\w]\S*)$/) {
|
|
Packit Service |
c5cf8c |
$subline = $1;
|
|
Packit Service |
c5cf8c |
$line = $2 . $line;
|
|
Packit Service |
c5cf8c |
# Add blanks to end of the subline to match what was stripped
|
|
Packit Service |
c5cf8c |
# off
|
|
Packit Service |
c5cf8c |
my $len = length($2);
|
|
Packit Service |
c5cf8c |
for (my $i=0; $i < $len; $i++) {
|
|
Packit Service |
c5cf8c |
$subline .= " ";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
print $OFD $subline . $postLine . "\n";
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
$line = substr $line, $maxPrintLine;
|
|
Packit Service |
c5cf8c |
$line = $preLine . $line;
|
|
Packit Service |
c5cf8c |
$length = length($line);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
print $OFD $line . "\n";
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
# --------------------------------------------------------------------------
|
|
Packit Service |
c5cf8c |
# Process the file
|
|
Packit Service |
c5cf8c |
# Still to do:
|
|
Packit Service |
c5cf8c |
# Allow multiple definition files, to allow for common definitions
|
|
Packit Service |
c5cf8c |
# for such things as headers
|
|
Packit Service |
c5cf8c |
my $defnFile = "";
|
|
Packit Service |
c5cf8c |
my $tmplFile = "";
|
|
Packit Service |
c5cf8c |
my $posCount = 0;
|
|
Packit Service |
c5cf8c |
for (@ARGV) {
|
|
Packit Service |
c5cf8c |
if (/-defn=(.*)/) {
|
|
Packit Service |
c5cf8c |
my $extraFile = $1;
|
|
Packit Service |
c5cf8c |
&ReadGlobalDefinitions( $extraFile );
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif (/-lang=(.*)/) {
|
|
Packit Service |
c5cf8c |
$lang = $1;
|
|
Packit Service |
c5cf8c |
if (!defined($knownLang{$lang})) {
|
|
Packit Service |
c5cf8c |
print STDERR "Unknown language $lang\n";
|
|
Packit Service |
c5cf8c |
exit 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif (/^-/) {
|
|
Packit Service |
c5cf8c |
print STDERR "Unrecognized argument $_\n";
|
|
Packit Service |
c5cf8c |
exit 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
else {
|
|
Packit Service |
c5cf8c |
if ($posCount == 0) {
|
|
Packit Service |
c5cf8c |
$defnFile = $_;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
elsif ($posCount == 1) {
|
|
Packit Service |
c5cf8c |
$tmplFile = $_;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
else {
|
|
Packit Service |
c5cf8c |
print STDERR "Too many arguments ($_)\n";
|
|
Packit Service |
c5cf8c |
exit 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
$posCount ++;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if ($defnFile eq "" || $tmplFile eq "") {
|
|
Packit Service |
c5cf8c |
print STDERR "testmerge [ -defn=name ] defintion-file template-file \n";
|
|
Packit Service |
c5cf8c |
exit 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
&ReadAndMerge( $defnFile, $tmplFile );
|