Blame maint/extractcvars

Packit 0848f5
#!/usr/bin/env perl
Packit 0848f5
#
Packit 0848f5
# (C) 2011by Argonne National Laboratory.
Packit 0848f5
#     See COPYRIGHT in top-level directory.
Packit 0848f5
#
Packit 0848f5
Packit 0848f5
# Parse C or header files to search for MPI_T control variable
Packit 0848f5
# and category info, then output the info in source code form.
Packit 0848f5
Packit 0848f5
use strict;
Packit 0848f5
use warnings;
Packit 0848f5
use File::Basename qw(basename);
Packit 0848f5
use Data::Dumper;
Packit 0848f5
use Getopt::Long;
Packit 0848f5
Packit 0848f5
# Help perl find the YAML parsing module
Packit 0848f5
use lib '/tmp/_HMuTRgPPE/mpich-3.2.1/maint/local_perl/lib';
Packit 0848f5
use YAML::Tiny qw();
Packit 0848f5
Packit 0848f5
# To format README file
Packit 0848f5
use Text::Wrap;
Packit 0848f5
$Text::Wrap::unexpand = 0; # disable hard tabs in output
Packit 0848f5
Packit 0848f5
##################################################
Packit 0848f5
Packit 0848f5
# set true to enable debug output
Packit 0848f5
my $debug = 0;
Packit 0848f5
my @cvars = ();
Packit 0848f5
my @categories=();
Packit 0848f5
my $yaml = YAML::Tiny->new();
Packit 0848f5
my @dirs = ();
Packit 0848f5
my @cfiles = ();
Packit 0848f5
my %skipfiles = ();
Packit 0848f5
Packit 0848f5
# namespace prefix for function names
Packit 0848f5
my $fn_ns = "MPIR_T_cvar";
Packit 0848f5
# namespace prefix for variable and type names
Packit 0848f5
my $ns = "MPIR_CVAR";
Packit 0848f5
# an alternative namespace used for environment variables, unused if set to ""
Packit 0848f5
my $alt_ns = "MPIR_PARAM";
Packit 0848f5
# deprecated prefix for backward compatibility
Packit 0848f5
my $dep_ns = "MPICH";
Packit 0848f5
Packit 0848f5
# Default :output source files
Packit 0848f5
my $header_file = "/tmp/_HMuTRgPPE/mpich-3.2.1/maint/../src/include/mpich_cvars.h";
Packit 0848f5
my $c_file      = "/tmp/_HMuTRgPPE/mpich-3.2.1/maint/../src/util/cvar/mpich_cvars.c";
Packit 0848f5
my $readme_file = "/tmp/_HMuTRgPPE/mpich-3.2.1/maint/../README.envvar";
Packit 0848f5
Packit 0848f5
sub Usage {
Packit 0848f5
    print <
Packit 0848f5
Packit 0848f5
Usage: $0 [OPTIONS]
Packit 0848f5
Packit 0848f5
Supported options:
Packit 0848f5
    --help              - this output (optional)
Packit 0848f5
    --debug             - enable some debugging output (optional)
Packit 0848f5
    --namespace=STR     - use STR as variable/type prefix in generated code (optional, default=$ns)
Packit 0848f5
    --alt-namespace=STR - use STR as alternaive variable/type prefix in generated code (optional, default=$alt_ns)
Packit 0848f5
    --header=STR        - specify the header file name (optional, default=$header_file)
Packit 0848f5
    --c-file=STR        - specify the C file name (optional, default=$c_file)
Packit 0848f5
    --readme-file=STR   - specify the readme file name (optional, default=$readme_file)
Packit 0848f5
    --dirs=STR          - recursively parse C or header files under the directories as specified
Packit 0848f5
    --skip=STR          - skip parsing files as specified (optional)
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
    exit 1;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Step 1: Process options
Packit 0848f5
my $dirline;
Packit 0848f5
my $skipline = "";
Packit 0848f5
GetOptions(
Packit 0848f5
    "help!"           => \&Usage,
Packit 0848f5
    "debug!"          => \$debug,
Packit 0848f5
    "namespace=s"     => \$ns,
Packit 0848f5
    "alt-namespace=s" => \$alt_ns,
Packit 0848f5
    "header=s"        => \$header_file,
Packit 0848f5
    "c-file=s"        => \$c_file,
Packit 0848f5
    "readme-file=s"   => \$readme_file,
Packit 0848f5
    "dirs=s"          => \$dirline,
Packit 0848f5
    "skips=s"         => \$skipline
Packit 0848f5
) or Usage();
Packit 0848f5
Packit 0848f5
Usage unless $dirline;
Packit 0848f5
Packit 0848f5
print "dirline = $dirline\n" if $debug;
Packit 0848f5
@dirs = split(/[:,;\s]+/, $dirline);
Packit 0848f5
Packit 0848f5
my @skips = split(/[:,;\s]+/, $skipline);
Packit 0848f5
%skipfiles = map {$_ => 1} @skips;
Packit 0848f5
Packit 0848f5
# Step 2: Search all cfiles and put them in @cfiles.
Packit 0848f5
foreach my $dir (@dirs) {
Packit 0848f5
    ExpandDir($dir);
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Step 3: Parse each cfile and put results in  @cvars and @categories.
Packit 0848f5
foreach my $cfile (@cfiles) {
Packit 0848f5
    ProcessFile($cfile);
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Step 4: Preprocess cvars:
Packit 0848f5
# *) Make sure that all categories referenced by cvars actually exist
Packit 0848f5
# *) Strip out the prefix of their name (normally, MPIR_CVAR)
Packit 0848f5
die "missing 'cvars', stopped" unless (@cvars);
Packit 0848f5
my %cat_hash = map {$_->{name} => 1} @categories;
Packit 0848f5
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    unless (exists $cat_hash{$p->{category}}) {
Packit 0848f5
        warn "Category '".$p->{category}."' referenced by '".$p->{name}."' was not found";
Packit 0848f5
    }
Packit 0848f5
    $p->{name} =~ s/${ns}_//;
Packit 0848f5
    if (exists $p->{'alt-env'}) {
Packit 0848f5
        my @alts = split(/[:,;\s]+/, $p->{'alt-env'});
Packit 0848f5
        foreach my $elmt (@alts) {
Packit 0848f5
            $elmt =~ s/${ns}_//;
Packit 0848f5
        }
Packit 0848f5
        $p->{'alt-env'} = [@alts];
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Step 5: Output cvars and categories
Packit 0848f5
print "Categories include: \n".Dumper(@categories) if $debug;
Packit 0848f5
print "Cvars include :\n".Dumper(@cvars)."\n" if $debug;
Packit 0848f5
Packit 0848f5
my $run_timestamp = localtime();
Packit 0848f5
my $uc_ns = uc($ns);
Packit 0848f5
Packit 0848f5
# Setup output files
Packit 0848f5
open(OUTPUT_H,      '>', $header_file);
Packit 0848f5
open(OUTPUT_C,      '>', $c_file);
Packit 0848f5
open(OUTPUT_README, '>', $readme_file);
Packit 0848f5
Packit 0848f5
#===============================================================
Packit 0848f5
# Step 5.1: Dump the header file.
Packit 0848f5
my $hdr_guard = Header2InclGuard($header_file);
Packit 0848f5
print OUTPUT_H <
Packit 0848f5
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit 0848f5
/*
Packit 0848f5
 *  (C) 2010 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
/* Automatically generated
Packit 0848f5
 *   by:   $0
Packit 0848f5
 *   on:   $run_timestamp
Packit 0848f5
 *
Packit 0848f5
 * DO NOT EDIT!!!
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
#if !defined($hdr_guard)
Packit 0848f5
#define $hdr_guard
Packit 0848f5
Packit 0848f5
#include "mpitimpl.h" /* for MPIR_T_cvar_range_value_t */
Packit 0848f5
Packit 0848f5
/* Initializes cvar values from the environment */
Packit 0848f5
int ${fn_ns}_init(void);
Packit 0848f5
int ${fn_ns}_finalize(void);
Packit 0848f5
Packit 0848f5
/* Extern declarations for each cvar
Packit 0848f5
 * (definitions in $c_file) */
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    printf OUTPUT_H "/* declared in $p->{location} */\n";
Packit 0848f5
    printf OUTPUT_H "extern %s ${uc_ns}_%s;\n", Type2Ctype($p->{type}), $p->{name};
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
print OUTPUT_H <
Packit 0848f5
Packit 0848f5
/* TODO: this should be defined elsewhere */
Packit 0848f5
#define ${ns}_assert MPIU_Assert
Packit 0848f5
Packit 0848f5
/* Arbitrary, simplifies interaction with external interfaces like MPI_T_ */
Packit 0848f5
#define ${uc_ns}_MAX_STRLEN (384)
Packit 0848f5
Packit 0848f5
#endif /* $hdr_guard */
Packit 0848f5
EOT
Packit 0848f5
close(OUTPUT_H);
Packit 0848f5
Packit 0848f5
#===============================================================
Packit 0848f5
# Step 5.2: Dump the C file.
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit 0848f5
/*
Packit 0848f5
 *  (C) 2010 by Argonne National Laboratory.
Packit 0848f5
 *      See COPYRIGHT in top-level directory.
Packit 0848f5
 */
Packit 0848f5
/* automatically generated
Packit 0848f5
 *   by:   $0
Packit 0848f5
 *   at:   $run_timestamp
Packit 0848f5
 *
Packit 0848f5
 * DO NOT EDIT!!!
Packit 0848f5
 */
Packit 0848f5
Packit 0848f5
#include "mpiimpl.h"
Packit 0848f5
Packit 0848f5
/* Actual storage for cvars */
Packit 0848f5
EOT
Packit 0848f5
# Output the definitions
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    my $default = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
Packit 0848f5
    if ($p->{class} eq 'device') {
Packit 0848f5
        printf OUTPUT_C "#if defined MPID_%s\n", $p->{name};
Packit 0848f5
        printf OUTPUT_C "%s ${uc_ns}_%s = MPID_%s;\n", Type2Ctype($p->{type}), $p->{name},
Packit 0848f5
                       $p->{name};
Packit 0848f5
        printf OUTPUT_C "#else\n";
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    if ($p->{type} eq 'string') {
Packit 0848f5
        printf OUTPUT_C "%s ${uc_ns}_%s = (char*)%s;\n", Type2Ctype($p->{type}), $p->{name}, $default;
Packit 0848f5
    } else {
Packit 0848f5
        printf OUTPUT_C "%s ${uc_ns}_%s = %s;\n", Type2Ctype($p->{type}), $p->{name}, $default;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    if ($p->{class} eq 'device') {
Packit 0848f5
        printf OUTPUT_C "#endif /* MPID_%s */\n\n", $p->{name};
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Generate the init function.
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
Packit 0848f5
#undef FUNCNAME
Packit 0848f5
#define FUNCNAME ${fn_ns}_init
Packit 0848f5
#undef FCNAME
Packit 0848f5
#define FCNAME MPL_QUOTE(FUNCNAME)
Packit 0848f5
int ${fn_ns}_init(void)
Packit 0848f5
{
Packit 0848f5
    int mpi_errno = MPI_SUCCESS;
Packit 0848f5
    int rc;
Packit 0848f5
    const char *tmp_str;
Packit 0848f5
    static int initialized = FALSE;
Packit 0848f5
    MPIR_T_cvar_value_t defaultval;
Packit 0848f5
Packit 0848f5
    /* FIXME any MT issues here? */
Packit 0848f5
    if (initialized)
Packit 0848f5
        return MPI_SUCCESS;
Packit 0848f5
    initialized = TRUE;
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
Packit 0848f5
# Register categories
Packit 0848f5
foreach my $cat (@categories) {
Packit 0848f5
    my $desc = $cat->{description};
Packit 0848f5
    $desc =~ s/"/\\"/g;
Packit 0848f5
    printf OUTPUT_C qq(    /* declared in $cat->{location} */\n);
Packit 0848f5
    printf OUTPUT_C qq(    MPIR_T_cat_add_desc(%s\n%s);\n\n),
Packit 0848f5
        qq("$cat->{name}",),
Packit 0848f5
        qq(        "$desc");
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Register and init cvars
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    my $count;
Packit 0848f5
    my $mpi_dtype;
Packit 0848f5
    my $dftval;
Packit 0848f5
Packit 0848f5
    # Set count and default value of the car
Packit 0848f5
    if ($p->{type} eq 'string') {
Packit 0848f5
        $mpi_dtype = "MPI_CHAR";
Packit 0848f5
        $count = "${uc_ns}_MAX_STRLEN";
Packit 0848f5
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
        printf OUTPUT_C qq(    defaultval.str = (char *)%s;\n), $dftval;
Packit 0848f5
    }
Packit 0848f5
    elsif ($p->{type} eq 'int' or $p->{type} eq 'boolean') {
Packit 0848f5
        $mpi_dtype = "MPI_INT";
Packit 0848f5
        $count = 1;
Packit 0848f5
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
        printf OUTPUT_C qq(    defaultval.d = %s;\n), $dftval;
Packit 0848f5
    }
Packit 0848f5
    elsif ($p->{type} eq 'double') {
Packit 0848f5
        $mpi_dtype = "MPI_DOUBLE";
Packit 0848f5
        $count = 1;
Packit 0848f5
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
        printf OUTPUT_C qq(    defaultval.d = %s;\n), $dftval;
Packit 0848f5
    }
Packit 0848f5
    elsif ($p->{type} eq 'range') {
Packit 0848f5
        $mpi_dtype = "MPI_INT";
Packit 0848f5
        $count = 2;
Packit 0848f5
        $dftval = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
        printf OUTPUT_C qq(    {\n);
Packit 0848f5
        printf OUTPUT_C qq(        MPIR_T_cvar_range_value_t tmp = %s;\n), $dftval;
Packit 0848f5
        printf OUTPUT_C qq(        defaultval.range = tmp;\n);
Packit 0848f5
        printf OUTPUT_C qq(    }\n);
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        die "unknown type $p->{type}, stopped";
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    # Register the cvar
Packit 0848f5
    my $desc = $p->{description};
Packit 0848f5
    $desc =~ s/"/\\"/g;
Packit 0848f5
    printf OUTPUT_C qq(    MPIR_T_CVAR_REGISTER_STATIC(\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s);\n),
Packit 0848f5
        qq(        $mpi_dtype,),
Packit 0848f5
        qq(        ${uc_ns}_$p->{name}, /* name */),
Packit 0848f5
        qq(        &${uc_ns}_$p->{name}, /* address */),
Packit 0848f5
        qq(        $count, /* count */),
Packit 0848f5
        qq(        $p->{verbosity},),
Packit 0848f5
        qq(        $p->{scope},),
Packit 0848f5
        qq(        defaultval,),
Packit 0848f5
        qq(        "$p->{category}", /* category */),
Packit 0848f5
        qq(        "$desc");
Packit 0848f5
Packit 0848f5
    if ($p->{type} eq 'string') {
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    ${uc_ns}_GET_DEFAULT_STRING(${uc_ns}_$p->{name}, &tmp_str);
Packit 0848f5
EOT
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    # Get the env variable value.
Packit 0848f5
    my $env_fn = Type2EnvFn($p->{type});
Packit 0848f5
    my @env_names = ();
Packit 0848f5
    my $var_name = "${uc_ns}_" . $p->{name};
Packit 0848f5
Packit 0848f5
    # Process extra envs first so the primary always wins
Packit 0848f5
    push @env_names, map { "${dep_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
    push @env_names, map { "${alt_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
    push @env_names, map { "${uc_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
    push @env_names, "${dep_ns}_" . $p->{name};
Packit 0848f5
    push @env_names, "${alt_ns}_" . $p->{name};
Packit 0848f5
    push @env_names, "${uc_ns}_" . $p->{name};
Packit 0848f5
Packit 0848f5
    foreach my $env_name (@env_names) {
Packit 0848f5
        # assumes rc is defined
Packit 0848f5
        if ($p->{type} eq 'range') {
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    rc = MPL_env2${env_fn}("$env_name", &($var_name.low), &($var_name.high));
Packit 0848f5
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit 0848f5
EOT
Packit 0848f5
        }
Packit 0848f5
        elsif ($p->{type} eq 'string') {
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    rc = MPL_env2${env_fn}("$env_name", &tmp_str);
Packit 0848f5
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit 0848f5
EOT
Packit 0848f5
        }
Packit 0848f5
        else {
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    rc = MPL_env2${env_fn}("$env_name", &($var_name));
Packit 0848f5
    MPIR_ERR_CHKANDJUMP1((-1 == rc),mpi_errno,MPI_ERR_OTHER,"**envvarparse","**envvarparse %s","$env_name");
Packit 0848f5
EOT
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    if ($p->{type} eq 'string') {
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    if (tmp_str != NULL) {
Packit 0848f5
        ${var_name} = MPIU_Strdup(tmp_str);
Packit 0848f5
        ${ns}_assert(${var_name});
Packit 0848f5
        if (${var_name} == NULL) {
Packit 0848f5
            MPIU_CHKMEM_SETERR(mpi_errno, strlen(tmp_str), "dup of string for ${var_name}");
Packit 0848f5
            goto fn_fail;
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        ${var_name} = NULL;
Packit 0848f5
    }
Packit 0848f5
EOT
Packit 0848f5
    }
Packit 0848f5
    print OUTPUT_C "\n";
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
fn_exit:
Packit 0848f5
    return mpi_errno;
Packit 0848f5
fn_fail:
Packit 0848f5
    goto fn_exit;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
int ${fn_ns}_finalize(void)
Packit 0848f5
{
Packit 0848f5
    int mpi_errno = MPI_SUCCESS;
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    my $var_name = "${uc_ns}_" . $p->{name};
Packit 0848f5
Packit 0848f5
    if ($p->{type} eq 'string') {
Packit 0848f5
        # Need to cleanup after whatever was strduped by the init routine
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
    if (${var_name} != NULL) {
Packit 0848f5
        MPIU_Free(${var_name});
Packit 0848f5
        ${var_name} = NULL;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
print OUTPUT_C <
Packit 0848f5
fn_exit:
Packit 0848f5
    return mpi_errno;
Packit 0848f5
fn_fail:
Packit 0848f5
    goto fn_exit;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
close(OUTPUT_C);
Packit 0848f5
Packit 0848f5
#===============================================================
Packit 0848f5
#Step 5.3 Dump the readme file
Packit 0848f5
print OUTPUT_README <
Packit 0848f5
(C) 2010 by Argonne National Laboratory.
Packit 0848f5
    See COPYRIGHT in top-level directory.
Packit 0848f5
Packit 0848f5
Automatically generated
Packit 0848f5
  by:   $0
Packit 0848f5
  at:   $run_timestamp
Packit 0848f5
DO NOT EDIT!!!
Packit 0848f5
Packit 0848f5
This file lists the various environment variables available to change the
Packit 0848f5
behavior of the MPICH library.  These are intended to be used by advanced
Packit 0848f5
users.
Packit 0848f5
---------------------------------------------------------------------------
Packit 0848f5
Packit 0848f5
EOT
Packit 0848f5
Packit 0848f5
foreach my $p (@cvars) {
Packit 0848f5
    my @env_names = ();
Packit 0848f5
    my $first;
Packit 0848f5
    my $alt;
Packit 0848f5
    my $default;
Packit 0848f5
Packit 0848f5
    # process extra envs first so the primary always wins
Packit 0848f5
    push @env_names, "${alt_ns}_" . $p->{name};
Packit 0848f5
    push @env_names, "${dep_ns}_" . $p->{name};
Packit 0848f5
    push @env_names, map { "${uc_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
    push @env_names, map { "${alt_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
    push @env_names, map { "${dep_ns}_$_" } @{$p->{'alt-env'}};
Packit 0848f5
Packit 0848f5
    print OUTPUT_README "${uc_ns}_$p->{name}\n";
Packit 0848f5
Packit 0848f5
    $first = 1;
Packit 0848f5
    foreach $alt (@env_names) {
Packit 0848f5
        if ($first) {
Packit 0848f5
            print OUTPUT_README "    Aliases: $alt\n";
Packit 0848f5
        } else {
Packit 0848f5
            print OUTPUT_README "             $alt\n";
Packit 0848f5
        }
Packit 0848f5
        $first = 0;
Packit 0848f5
    }
Packit 0848f5
Packit 0848f5
    print OUTPUT_README wrap("    Description: ", "        ", $p->{description} . "\n");
Packit 0848f5
    $default = FmtDefault($p->{name}, $p->{default}, $p->{type});
Packit 0848f5
    print OUTPUT_README "    Default: $default\n";
Packit 0848f5
    print OUTPUT_README "\n";
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
close(OUTPUT_README);
Packit 0848f5
Packit 0848f5
#===============================================================
Packit 0848f5
# Helper subroutines used in this script
Packit 0848f5
Packit 0848f5
# Transform a cvar type to a C-language type
Packit 0848f5
sub Type2Ctype {
Packit 0848f5
    my $type = shift;
Packit 0848f5
    my %typemap = (
Packit 0848f5
        'int'     => 'int',
Packit 0848f5
        'double'  => 'double',
Packit 0848f5
        'string'  => 'char *',
Packit 0848f5
        'boolean' => 'int',
Packit 0848f5
        'range'   => "MPIR_T_cvar_range_value_t",
Packit 0848f5
    );
Packit 0848f5
    die "unknown type '$type', stopped" unless exists $typemap{$type};
Packit 0848f5
    return $typemap{$type};
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Transform a default value into a C value
Packit 0848f5
sub FmtDefault {
Packit 0848f5
    my $name = shift;
Packit 0848f5
    my $val = shift;
Packit 0848f5
    my $type = shift;
Packit 0848f5
Packit 0848f5
    if ($type eq 'string') {
Packit 0848f5
        $val =~ s/"/\\"/g;
Packit 0848f5
        if ($val eq 'NULL' or $val eq 'null') { return "NULL"; }
Packit 0848f5
        else { return qq("$val"); }
Packit 0848f5
    }
Packit 0848f5
    elsif ($type eq 'boolean') {
Packit 0848f5
        if    ($val =~ m/^(0|f(alse)?|no?)$/i)   { return qq(0); }
Packit 0848f5
        elsif ($val =~ m/^(1|t(rue)?|y(es)?)$/i) { return qq(1); }
Packit 0848f5
        else {
Packit 0848f5
            warn "WARNING: type='$type', bad val='$val', continuing";
Packit 0848f5
            return qq(0); # fail-false
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    elsif ($type eq 'range') {
Packit 0848f5
        if ($val !~ "-?[0-9]+:-?[0-9]+") {
Packit 0848f5
            die "Unable to parse range value '$val', stopped";
Packit 0848f5
        }
Packit 0848f5
        $val =~ s/:/,/;
Packit 0848f5
        return qq({$val});
Packit 0848f5
    }
Packit 0848f5
    else {
Packit 0848f5
        return qq($val);
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# turns /path/foo_BAR-baz.h into FOO_BAR_BAZ_H_INCLUDED
Packit 0848f5
sub Header2InclGuard {
Packit 0848f5
    my $header_file = shift;
Packit 0848f5
    my $guard = basename($header_file);
Packit 0848f5
    $guard =~ tr/a-z\-./A-Z__/;
Packit 0848f5
    $guard .= "_INCLUDED";
Packit 0848f5
    die "guard contains whitespace, stopped" if ($guard =~ m/\s/);
Packit 0848f5
    return $guard;
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
sub Type2EnvFn {
Packit 0848f5
    my $type = shift;
Packit 0848f5
    my %typemap = (
Packit 0848f5
        'int' =>  'int',
Packit 0848f5
        'string' => 'str',
Packit 0848f5
        'boolean' => 'bool',
Packit 0848f5
        'double' => 'double',
Packit 0848f5
        'range' => 'range',
Packit 0848f5
    );
Packit 0848f5
Packit 0848f5
    die "unknown type '$type', stopped" unless exists $typemap{$type};
Packit 0848f5
    return $typemap{$type};
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Parse a file, search the MPI_T_CVAR_INFO_BLOCK if any.
Packit 0848f5
# Distill cvars and categories from the block.
Packit 0848f5
# Push the results to back of @cvars and @categories respectively.
Packit 0848f5
sub ProcessFile {
Packit 0848f5
    my $cfile = $_[0];
Packit 0848f5
    my $cvar_info_block = undef;
Packit 0848f5
    my $in_cvar_info_block = 0;
Packit 0848f5
Packit 0848f5
    #print "Processing file $cfile\n" if $debug;
Packit 0848f5
    open my $CFILE_HANDLE, "< $cfile" or die "Error: open file $cfile -- $!\n";
Packit 0848f5
    while (<$CFILE_HANDLE>) {
Packit 0848f5
        if (/END_MPI_T_CVAR_INFO_BLOCK/) {
Packit 0848f5
            last;
Packit 0848f5
        } elsif ($in_cvar_info_block) {
Packit 0848f5
            $cvar_info_block .= $_;
Packit 0848f5
        } elsif (/BEGIN_MPI_T_CVAR_INFO_BLOCK/) {
Packit 0848f5
            $in_cvar_info_block = 1;
Packit 0848f5
            print "Found MPI_T_CVAR_INFO_BLOCK in $cfile\n" if $debug;
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    close $CFILE_HANDLE;
Packit 0848f5
Packit 0848f5
    # Do some checking to ensure a correct cvar info block, also
Packit 0848f5
    # add file locations to help users' debugging.
Packit 0848f5
    if ($cvar_info_block) {
Packit 0848f5
        my $info = ($yaml->read_string($cvar_info_block))->[0];
Packit 0848f5
        if (exists $info->{cvars}) {
Packit 0848f5
            # Remember location where the cvar is defined. Put that into
Packit 0848f5
            # comments of the generated *.h file so that users know where
Packit 0848f5
            # to look when meeting compilation errors.
Packit 0848f5
            foreach my $cvar (@{$info->{cvars}}) {
Packit 0848f5
                $cvar->{location} = $cfile;
Packit 0848f5
                die "ERROR: cvar has no name in $cfile\n" unless exists $cvar->{name};
Packit 0848f5
                die "ERROR: cvar $cvar->{name} has no type in $cfile\n" unless exists $cvar->{type};
Packit 0848f5
                die "ERROR: cvar $cvar->{name} has no verbosity in $cfile\n" unless exists $cvar->{verbosity};
Packit 0848f5
                die "ERROR: cvar $cvar->{name} has no scope in $cfile\n" unless exists $cvar->{scope};
Packit 0848f5
                die "ERROR: cvar $cvar->{name} has no class in $cfile\n" unless exists $cvar->{class};
Packit 0848f5
                die "ERROR: cvar $cvar->{name} has no description in $cfile\n" unless exists $cvar->{description};
Packit 0848f5
            }
Packit 0848f5
            push (@cvars, @{$info->{cvars}});
Packit 0848f5
        }
Packit 0848f5
Packit 0848f5
        if (exists $info->{categories}) {
Packit 0848f5
            # Do the same trick to categories
Packit 0848f5
            foreach my $cat (@{$info->{categories}}) {
Packit 0848f5
                $cat->{location} = $cfile;
Packit 0848f5
                die "ERROR: category has no name in $cfile\n" unless exists $cat->{name};
Packit 0848f5
                die "ERROR: category $cat->{name} has no description in $cfile\n"
Packit 0848f5
                    unless exists $cat->{description};
Packit 0848f5
            }
Packit 0848f5
            push (@categories, @{$info->{categories}});
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
}
Packit 0848f5
Packit 0848f5
# Search cfiles recursively in the directory passed in.
Packit 0848f5
# Push file names along with their paths to back of @cfiles.
Packit 0848f5
sub ExpandDir {
Packit 0848f5
    my $dir = $_[0];
Packit 0848f5
    my @subdirs = ();
Packit 0848f5
    my $DIR_HANDLE;
Packit 0848f5
    opendir $DIR_HANDLE, "$dir" or die "Error: open directory $dir -- $!\n";
Packit 0848f5
    while (my $filename = readdir $DIR_HANDLE) {
Packit 0848f5
        if ($filename =~ /^\./) {
Packit 0848f5
            next;
Packit 0848f5
        } elsif (-d "$dir/$filename") {
Packit 0848f5
            $subdirs[$#subdirs + 1] = "$dir/$filename";
Packit 0848f5
        } elsif ($filename =~ /(.*\.[Cchi])(pp){0,1}$/) {
Packit 0848f5
            if (!defined($skipfiles{"$dir/$filename"}))
Packit 0848f5
            {
Packit 0848f5
                $cfiles[$#cfiles + 1] = "$dir/$filename";
Packit 0848f5
            }
Packit 0848f5
        }
Packit 0848f5
    }
Packit 0848f5
    closedir $DIR_HANDLE;
Packit 0848f5
Packit 0848f5
    # Recursively search subdirs
Packit 0848f5
    foreach $dir (@subdirs) {
Packit 0848f5
        ExpandDir($dir);
Packit 0848f5
    }
Packit 0848f5
}