Subversion Repositories DevTools

Rev

Rev 377 | Blame | Compare with Previous | Last modification | View Log | RSS feed

########################################################################
# Copyright (C) 1998-2012 Vix Technology, All rights reserved
#
# Module name   : jats.sh
# Module type   : Makefile system
# Compiler(s)   : n/a
# Environment(s): jats
#
# Description   : Provide varions functions used by the BuildVersion
#                 directive.
#
#                 Use only within buildlib.pl as this package assumes
#                 a great deal about its environment.
#
#......................................................................#

require 5.006_001;
use strict;
use warnings;

our $Clobber;
our $CurrentYear;
our $CurrentTime;
our $Srcdir;
our $BuildVersion;
our $BUILDNAME;
our $BUILDNAME_PACKAGE;
our $BUILDNAME_VERSION;
our $BUILDNAME_PROJECT;

package BuildVersion;
use JatsError;
use JatsSystem;
use JatsVersionUtils;
use ConfigurationFile;
use FileUtils;

#
#   Package Interface
#
use base qw(Exporter);
our @EXPORT = qw( BuildVersionC
              BuildVersionCdefs
              BuildVersionCSharp
              BuildVersionWinRC
              BuildVersionProperties
              BuildVersionDelphi
              BuildVersionVB
            );

################################################################################
#   The following strings have been obtained from Simon Davey in an email
#   to David Purdie dated Monday, 16 January 2012 3:40 PM
#
#   Note: At 'init' time, the $CurrentDate is not valid
#         It must be injected later
#
my $CompanyName = 'Vix IP Pty Ltd';
my $Copyright = $CompanyName;                   # Will have $CurrentDate appended
my $Trademark = $CompanyName;
#
################################################################################

#-------------------------------------------------------------------------------
# Function        : BuildVersionCSharp
#
# Description     : Generate a C# versionn information file to allow
#                   insertion of data into an assembly
#
# Inputs          : $FileName           - Output filename (Optional)
#
# Returns         :
#
sub BuildVersionCSharp
{
    my ( $fname ) = @_;
    $fname = 'AssemblyVersionInfo.cs' unless $fname;

    #
    #   Store the files location for use at runtime
    #   It will be a file that is 'known' to JATS
    #
    $fname = ::BuildAddKnownFile ( $Srcdir, $fname );
    return if ( $Clobber );      # clobber mode ?
    Message ("Creating C# Version File: $fname" );

    #
    #   Determine the build version
    #
    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($BUILDNAME_VERSION);
    my $vstring = "$major.$minor.$patch.$build";


    my $fh = ConfigurationFile::New( $fname, '--Type=CSharp' );
    $fh->HeaderSimple( "buildlib (Version $BuildVersion)",
                       "CSharp Assembly Version Definition" );

    $fh->Write( "\n" );
    $fh->Write( "using System.Reflection;\n" );
    $fh->Write( "using System.Runtime.CompilerServices;\n" );
    $fh->Write( "\n" );
    $fh->Write( "[assembly: AssemblyCompany(\"$CompanyName\")]\n" );
    $fh->Write( "[assembly: AssemblyProduct(\"$BUILDNAME_PACKAGE\")]\n" );
    $fh->Write( "[assembly: AssemblyCopyright(\"$Copyright $CurrentYear\")]\n" );
    $fh->Write( "[assembly: AssemblyTrademark(\"$Trademark\")]\n" );
    $fh->Write( "\n");
    $fh->Comment( "\n");
    $fh->Comment( "Version information for an assembly consists of the following four values:\n");
    $fh->Comment( "\n");
    $fh->Comment( "     Major Version   -VIX:Major\n");
    $fh->Comment( "     Minor Version  - VIX:Minor\n");
    $fh->Comment( "     Build Number   - VIX:Patch\n");
    $fh->Comment( "     Revision       - VIX:Build Number\n");
    $fh->Comment( "\n");
    $fh->Write( "\n");
    $fh->Write( "[assembly: AssemblyVersion(\"$vstring\")]\n" );
    $fh->Write( "\n");

    $fh->Close();
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionWinRC
#
# Description     : Create a Windows RC file to describe the build version
#                   This file may be used directly
#
# Inputs          : $FileName           - Output filename (Optional)
#                   @opts               - Options
#                           --Definitions
#                           --Icon=path
#                           --Comment=text
#                           --Description=text
#                           --Product=text
#                           --Version=text          (Internal Use)
#                           --PkgName=text          (Internal Use)
#                           --ToolUse               (Internal Use)
# Returns         : Nothing
#
sub BuildVersionWinRC
{
    my ( $fname, @opts ) = @_;
    my $icon;
    my $defs;
    my $product = '';
    my $version = $BUILDNAME_VERSION || '';
    my $pkg_name = $BUILDNAME_PACKAGE || '';
    my $comment = "Build Date: $CurrentTime";
    my $description = '';
    my $used_by_tool = '';

    #
    #   Process options
    #
    foreach ( @opts )
    {
        if ( m~^--Icon=(.+)~ ) {
            $icon = $1;
        } elsif ( m~^--Definitions~ ) {
            $defs = 1;
        } elsif ( m~^--Comment=(.+)~ ) {
            $comment = $1;
        } elsif ( m~^--Description=(.+)~ ) {
            $description = $1;
        } elsif ( m~^--Product=(.+)~ ) {
            $product = $1;
        } elsif ( m~^--Version=(.+)~ ) {
            $version = $1;
        } elsif ( m~^--PkgName=(.+)~ ) {
            $pkg_name = $1;
        } elsif ( m~^--ToolUse~ ) {
            $used_by_tool = 1;
        } else {
            Error ("WinRC Style Version. Unknown option: $_");
        }
    }

    #
    #   Setup defaults
    #
    $fname = 'version.rc' unless $fname;
    Error ("WinRC: No Build Version provided") unless ( $version );
    Error ("WinRC: No Build Package Name provided") unless ( $pkg_name );

    #
    #   Store the files location for use at runtime
    #   It will be a file that is 'known' to JATS
    #
    unless ( $used_by_tool  )
    {
        $fname = ::BuildAddKnownFile ( $Srcdir, $fname );
        return if ( $Clobber );      # clobber mode ?
    }

    Message ("Creating Windows Resource File: $fname" );

    #
    #   Determine the build version
    #
    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($version);
    my $product_version = "$major, $minor, $patch, $build";
    

    #
    #   Create the file
    #
    my $fh = ConfigurationFile::New( $fname, '--Type=C++' );
    $fh->HeaderSimple( "buildlib (Version $BuildVersion)",
                       "Windows Resource Version Definition" );

    sub prc
    {
        return "@_\n";
    }

    sub pdefs
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return "#define $arg \"$val\\0\"\n";
    }

    sub pdef
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return "#define $arg $val\n";
    }

    $fh->Write(prc     (""));
    $fh->Write(pdefs   ("RC_STR_EMPTY"         , "" ));
    $fh->Write(pdefs   ("RC_STR_COMPANY"       , $CompanyName ));
    $fh->Write(pdefs   ("RC_STR_PRODUCTNAME"   , $product ));
    $fh->Write(pdefs   ("RC_STR_COMMENT"       , $comment ));
    $fh->Write(pdefs   ("RC_STR_DESCRIPTION"   , $description ));
    $fh->Write(pdefs   ("RC_STR_NAME"          , $pkg_name ));
    $fh->Write(pdefs   ("RC_STR_VERSION"       , $product_version ));
    $fh->Write(pdef    ("RC_NUM_VERSION"       , $product_version ));
    $fh->Write(pdefs   ("RC_STR_COPYRIGHT"     , $Copyright . ' ' . $::CurrentYear ));
    $fh->Write(pdefs   ("RC_STR_TRADEMARK"     , $Trademark ));
    $fh->Write(prc     ('#ifdef _DEBUG'));
    $fh->Write(pdefs   ("RC_STR_SPECIAL"       , "Debug Version" ));
    $fh->Write(prc     ('#else'));
    $fh->Write(pdefs   ("RC_STR_SPECIAL"       , "Production Version" ));
    $fh->Write(prc     ('#endif'));
    $fh->Write(prc     (""));

    unless ( $defs )
    {
        $fh->Write(prc     ('#define VS_VERSION_INFO     1'));
        $fh->Write(prc     (''));
        $fh->Write(prc     ('VS_VERSION_INFO VERSIONINFO'));
        $fh->Write(prc     (' FILEVERSION      RC_NUM_VERSION'));
        $fh->Write(prc     (' PRODUCTVERSION   RC_NUM_VERSION'));
        $fh->Write(prc     (' FILEFLAGSMASK 0x3fL'));
        $fh->Write(prc     ('#ifdef _DEBUG'));
        $fh->Write(prc     (' FILEFLAGS 0x1L'));
        $fh->Write(prc     ('#else'));
        $fh->Write(prc     (' FILEFLAGS 0x0L'));
        $fh->Write(prc     ('#endif'));
        $fh->Write(prc     (' FILEOS 0x40004L'));
        $fh->Write(prc     (' FILETYPE 0x1L'));
        $fh->Write(prc     (' FILESUBTYPE 0x0L'));
        $fh->Write(prc     ('BEGIN'));
        $fh->Write(prc     ('    BLOCK "StringFileInfo"'));
        $fh->Write(prc     ('    BEGIN'));
        $fh->Write(prc     ('        BLOCK "0c0904b0"'));
        $fh->Write(prc     ('        BEGIN'));
        $fh->Write(prc     ('            VALUE "Comments",         RC_STR_COMMENT'));
        $fh->Write(prc     ('            VALUE "CompanyName",      RC_STR_COMPANY'));
        $fh->Write(prc     ('            VALUE "FileDescription",  RC_STR_DESCRIPTION'));
        $fh->Write(prc     ('            VALUE "FileVersion",      RC_STR_VERSION'));
        $fh->Write(prc     ('            VALUE "InternalName",     RC_STR_NAME'));
        $fh->Write(prc     ('            VALUE "LegalCopyright",   RC_STR_COPYRIGHT'));
        $fh->Write(prc     ('            VALUE "LegalTrademarks",  RC_STR_TRADEMARK'));
        $fh->Write(prc     ('            VALUE "OriginalFilename", RC_STR_NAME'));
        $fh->Write(prc     ('            VALUE "PrivateBuild",     RC_STR_EMPTY'));
        $fh->Write(prc     ('            VALUE "ProductName",      RC_STR_PRODUCTNAME'));
        $fh->Write(prc     ('            VALUE "ProductVersion",   RC_STR_VERSION'));
        $fh->Write(prc     ('            VALUE "SpecialBuild",     RC_STR_SPECIAL'));
        $fh->Write(prc     ('        END'));
        $fh->Write(prc     ('    END'));
        $fh->Write(prc     ('        BLOCK "VarFileInfo"'));
        $fh->Write(prc     ('        BEGIN'));
        $fh->Write(prc     ('            VALUE "Translation", 0xc09, 1200'));
        $fh->Write(prc     ('        END'));
        $fh->Write(prc     ('END'));
        $fh->Write(prc     (''));

        if ( $icon )
        {
        $fh->Write(prc     (''));
        $fh->Write(prc     ('/////////////////////////////////////////////////////////////////////////////'));
        $fh->Write(prc     ('//'));
        $fh->Write(prc     ('// Icon'));
        $fh->Write(prc     ('//'));
        $fh->Write(prc     ('// Icon with lowest ID value placed first to ensure application icon'));
        $fh->Write(prc     ('// remains consistent on all systems.'));
        $fh->Write(prc     ("101       ICON    DISCARDABLE     \"$icon\""));
        $fh->Write(prc     (''));
        }
    }
    

    $fh->Close();
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionC
#
# Description     : Create a "C" style version.c and version.h file
#
# Inputs          : $FileName       - Output filename (Optional)
#                                     If provided it will be 'known' to all
#                                     of jats. Done for backward compatability
#                   $Prefix         - Text to prefix generated variables with
#                                     Used to avoid namespace conflicts
#                   $Type           - Type of version to create
#                                     Only allowed value is 'array'
#
# Returns         :
#

sub BuildVersionC
{
    my( $FileName, $Prefix, $Type ) = @_;
    my $ver;

    #
    #   Default name of the file
    #   Don't allow the user to play with the extension
    #   If the user provided a filename It will be a file that is 'known' to JATS
    #   
    my $bname = defined($FileName) ? StripExt($FileName) : 'version';

    my $fname_c = ::BuildAddKnownFile ( $Srcdir, $bname . '.c', !defined($FileName) );
    my $fname_h = ::BuildAddKnownFile ( $Srcdir, $bname . '.h', !defined($FileName) );

    return if ( $Clobber );      # clobber mode ?
    Message ("Creating C Version File: $fname_c" );

    #
    #   Default prefix is none
    #   Set to a defined, bet empty, string
    #
    $Prefix = "" if ( ! defined( $Prefix ) );
    $Type   = "" if ( ! defined( $Type ) );

    #   src/version.c
    #..
    open( VERSIONC, '>', $fname_c ) ||
        Error( "cannot create $fname_c" );

    print VERSIONC
        "/* Please do not edit this file.\n" .
        " * It was auto-generated by Buildlib ($BuildVersion) on $::CurrentTime\n" .
        " */\n" .
        "#include \"version.h\"\n";

    print VERSIONC
        "\n" .
        "static char what[] = \"@(#) $BUILDNAME $::CurrentDate $CompanyName\";\n" .
        "\n";


    my @PACKAGEVERS = PackageEntry::GetPackageVersionList();
    if ( $Type eq "array" )
    {                                           # new style
        print VERSIONC
           "static const char *pkgarray[] = \n" .
           "{\n";

        foreach $ver ( @PACKAGEVERS   ) {
            print VERSIONC "    \"$ver\",\n";
        }

        print VERSIONC
           "    0\n",
           "};\n\n";

        print VERSIONC
           "\nconst char *\n$Prefix"."VersionString(void)\n" .
           "{\n".
           "    return \"$BUILDNAME\";\n" .
           "}\n" .
           "\nconst char **\n$Prefix"."PkgStrings(void)\n" .
           "{\n".
           "    return pkgarray;\n" .
           "}\n" .
           "\nconst char *\n$Prefix"."GetModuleInfo(void)\n" .
           "{\n" .
           "    return \"$BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS\";\n" .
           "}\n";
    }
    else
    {                                           # old style
        print VERSIONC
           "\nconst char *\n$Prefix"."VersionString(void)\n" .
           "{\n".
           "    return \"$BUILDNAME @PACKAGEVERS\";\n" .
           "}\n" .
           "\nconst char *\n$Prefix"."GetModuleInfo(void)\n" .
           "{\n" .
           "    return \"$BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS\";\n" .
           "}\n";
    }
    close VERSIONC;

#   src/version.h
#..
    open( VERSIONH, '>', $fname_h ) ||
        Error( "cannot create $fname_h" );

    print VERSIONH
        "#ifndef VERSION_H_INCLUDED\n" .
        "#define VERSION_H_INCLUDED\n" .
        "/* Please do not edit this file.\n" .
        " * It was auto-generated by Buildlib ($BuildVersion) on $::CurrentTime\n" .
        " */\n\n" .
        "#define BUILDNAME     \"$BUILDNAME\"\n" .
        "#define BUILDDATE     \"$::CurrentTime\"\n" .
        "\n";

    print VERSIONH
        "#ifdef __cplusplus\n" .
        "    extern \"C\" {           /* force C calling convention when using C++ */\n" .
        "#endif\n" .
        "\n";

    if ( $Type eq "array" )
    {                                           # extended interface
        print VERSIONH
        "extern const char **  $Prefix"."PkgStrings(void);\n";
    }
    print VERSIONH
        "extern const char *   $Prefix"."VersionString(void);\n".
        "extern const char *   $Prefix"."GetModuleInfo(void);\n";

    print VERSIONH
        "\n" .
        "#ifdef __cplusplus\n" .
        "    } /* extern \"C\" */\n" .
        "#endif\n" .
        "\n";

    print VERSIONH
        "\n#endif /*VERSION_H_INCLUDED*/\n";
    close VERSIONH;
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionCdefs
#
# Description     : Generate a "C" style version definitions file
#                   This file simply contains definitions
#
# Inputs          : $FileName       - Output filename (Optional)
#                                     If provided it will be 'known' to all
#                                     of jats. Done for backward compatability
#                   $Mode           - File suffix
#                   $ModePrefix     - Tag for all generated definitions
#
# Returns         :
#

sub BuildVersionCdefs
{
    my ( $FileName, $Mode, $ModePrefix ) = @_;

    my $fname = defined($FileName) ? $FileName : "version_$Mode.h";
    $fname = ::BuildAddKnownFile ( $Srcdir, $fname , ! defined($FileName) );
    return if ( $Clobber );      # clobber mode ?
    Message ("Creating C Version Defs File: $fname" );

    #
    #   Generate version_defs.h
    #   This file contains ONLY definitions. It may be used by assembler
    #   programs (that support a preprocessor) to access version information
    #
    #   Allow for a user supplied filename fragment that will be used within
    #   all the definitions with in the file.
    #
    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($BUILDNAME_VERSION);
    my @PACKAGEVERS = PackageEntry::GetPackageVersionList();

    #
    #   Base names on a user supplied value or a default
    #
    my $vtag = uc( "VERSION$ModePrefix" );
    my $guard_name = uc($fname);
       $guard_name =~ tr~\.\/\\~_~s;

    open( VERSIOND, '>', $fname ) ||
        Error( "cannot create $fname" );

    print VERSIOND
        "#ifndef $guard_name\n" .
        "#define $guard_name\n" .
        "/* Please do not edit this file.\n" .
        " * It was auto-generated by Buildlib ($BuildVersion) on $::CurrentTime\n" .
        " */\n\n" .
        "\n".
        "#define ${vtag}_BUILDNAME      \"$BUILDNAME\"\n".
        "#define ${vtag}_BUILDDATE      \"$::CurrentTime\"\n".
        "\n".
        "#define ${vtag}_PACKAGE        \"$BUILDNAME_PACKAGE\"\n".
        "#define ${vtag}_VERSION        \"$BUILDNAME_VERSION\"\n".
        "#define ${vtag}_MAJOR_STR      \"$major\"\n".
        "#define ${vtag}_MINOR_STR      \"$minor\"\n".
        "#define ${vtag}_PATCH_STR      \"$patch\"\n".
        "#define ${vtag}_BUILD_STR      \"$build\"\n".
        "#define ${vtag}_PATCHBUILD_STR \"$raw_patch\"\n".
        "#define ${vtag}_PROJECT        \"$BUILDNAME_PROJECT\"\n".
        "#define ${vtag}_MAJOR          $major\n".
        "#define ${vtag}_MINOR          $minor\n".
        "#define ${vtag}_PATCH          $patch\n".
        "#define ${vtag}_BUILD          $build\n".
        "#define ${vtag}_PATCHBUILD     $raw_patch\n".
        "#define ${vtag}_ALL            \"$BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS\"\n".
        "#define ${vtag}_BUILDTIME      " . strip_zeros(time()) . "\n".
        "\n".
        "#endif /* $guard_name */\n";

    close VERSIOND;
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionProperties
#
# Description     : Generate a "Java" style version definitions file
#                   This is a simple properties file
#
# Inputs          : $FileName       - Output filename (Optional)
#                   $Prefix         - Tag for all generated definitions
#
# Returns         :
#
sub BuildVersionProperties
{
    my ( $fname, $Prefix ) = @_;

    #
    #   Default name of the file
    #
    $fname = 'version.properties' unless $fname;

    #
    #   Store the files location for use at runtime
    #   It will be a file that is 'known' to JATS
    #
    $fname = ::BuildAddKnownFile ( $Srcdir, $fname );
    return if ( $Clobber );      # clobber mode ?
    Message ("Creating Properties Version File: $fname" );

    #
    #   Generate version properties file
    #
    #   This file contains ONLY definitions. It may be included by the ANT
    #   builds. Its not intended to be imported by the java code


    #
    #   Allow for a user supplied property prefix
    #   Not really needed as
    #
    my $vtag = '';
    $vtag = $Prefix . '.' if $Prefix;


    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($BUILDNAME_VERSION);
    my @PACKAGEVERS = PackageEntry::GetPackageVersionList();

    #
    #   Create properties in the same form as for "C" definitions
    #   Note:
    #       The 'ALL' is in a format used by other software. Do not change
    #
    open( VERSIOND, ">$fname" ) ||
        Error( "cannot create $fname" );

    print VERSIOND
        "# Please do not edit this file.\n" .
        "# It was auto-generated by Buildlib ($BuildVersion) on $::CurrentTime\n" .
        "#\n" .
        "${vtag}BUILDNAME      = $BUILDNAME\n".
        "${vtag}BUILDDATE      = $::CurrentTime\n".
        "\n".
        "${vtag}PACKAGE        = $BUILDNAME_PACKAGE\n".
        "${vtag}VERSION        = $BUILDNAME_VERSION\n".
        "${vtag}MAJOR_STR      = $major\n".
        "${vtag}MINOR_STR      = $minor\n".
        "${vtag}PATCH_STR      = $patch\n".
        "${vtag}BUILD_STR      = $build\n".
        "${vtag}PATCHBUILD_STR = $raw_patch\n".
        "${vtag}PROJECT        = $BUILDNAME_PROJECT\n".
        "${vtag}MAJOR          = $major\n".
        "${vtag}MINOR          = $minor\n".
        "${vtag}PATCH          = $patch\n".
        "${vtag}BUILD          = $build\n".
        "${vtag}PATCHBUILD     = $raw_patch\n".
        "${vtag}ALL            = $BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS\n".
        "${vtag}BUILDTIME      = " . strip_zeros(time()) . "\n".
        "\n";
    #
    #   Create a set of definitions for each dependent package
    #
    print VERSIOND "# Dependent Packages and Versions\n".
                   "#\n";
    
    foreach my $tag ( PackageEntry::GetPackageList() )
    {
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
#        push @attributes, "build=\"true\"" if $type =~ /Build/i;
        print VERSIOND "${vtag}PACKAGE.$name=$version\n";
    }
    close VERSIOND;
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionDelphi
#
# Description     : Create a pascal file in Delphi format
#
# Inputs          : $FileName       - Output filename (Optional)
#                   $Prefix         - Tag for all generated definitions
#
#
# Returns         : 
#
sub BuildVersionDelphi
{
    my ( $fname, $Prefix ) = @_;

    #
    #   Default name of the file
    #
    $fname = 'version_defs.pas' unless $fname;
    $fname .= '.pas'
        unless ( $fname =~ m~\.~ );
    my $unit_name = StripDirExt($fname);
    Error ("BuildVersion: Delphi Style. Filename \'$unit_name\. not allowed")
        if ( $unit_name =~ m~^version$~i );

    #
    #   Store the files location for use at runtime
    #   It will be a file that is 'known' to JATS
    #
    $fname = ::BuildAddKnownFile ( $Srcdir, $fname );
    return if ( $Clobber );      # clobber mode ?
    Message ("Creating Delpi Version File: $fname" );

    #
    #   Generate version source file
    #   This file contains ONLY constant definitions.

    #
    #   Allow for a user supplied property prefix
    #   Not really needed as
    #
    my $vtag = '';
    $vtag = $Prefix . '_' if $Prefix;


    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($BUILDNAME_VERSION);
    my @PACKAGEVERS = PackageEntry::GetPackageVersionList();

    #
    #   Create properties in the same form as for "C" definitions
    #   Note:
    #       The 'ALL' is in a format used by other software. Do not change
    #
    sub pstring
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return sprintf ( "%-24s = \'%s\';" , $arg, $val);
    }
    sub pnum
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return sprintf ( "%-24s = %s;" , $arg, $val );
    }

    my $fh = ConfigurationFile::New( $fname, '--Type=Delphi' );
    $fh->HeaderSimple( "buildlib (Version $BuildVersion)",
                       "Delphi Unit Version Definition" );

    $fh->WriteLn(
        "unit $unit_name;",
        "interface",
        "const",
        pstring ("${vtag}BUILDNAME",$BUILDNAME),
        pstring ("${vtag}BUILDDATE",$::CurrentTime),
        '',
        pstring ("${vtag}PACKAGE",$BUILDNAME_PACKAGE),
        pstring ("${vtag}VERSION",$BUILDNAME_VERSION),
        pstring ("${vtag}MAJOR_STR",$major),
        pstring ("${vtag}MINOR_STR",$minor),
        pstring ("${vtag}PATCH_STR",$patch),
        pstring ("${vtag}BUILD_STR",$build),
        pstring ("${vtag}PATCHBUILD_STR",$raw_patch),
        pstring ("${vtag}PROJECT",$BUILDNAME_PROJECT),
        pnum ("${vtag}MAJOR",$major),
        pnum ("${vtag}MINOR",$minor),
        pnum ("${vtag}PATCH",$patch),
        pnum ("${vtag}BUILD",$build),
        pnum ("${vtag}PATCHBUILD",$raw_patch),
        pstring ("${vtag}ALL","$BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS"),
        pnum ("${vtag}BUILDTIME",strip_zeros(time())),
        ''
        );

    #
    #   Create a set of definitions for each dependent package
    #
    $fh->Comment("Dependent Packages and Versions\n");
    $fh->Comment("\n");

    foreach my $tag ( PackageEntry::GetPackageList() )
    {
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
        $fh->WriteLn(pstring ("${vtag}PACKAGE_$name", $version));
    }
    $fh->WriteLn( '',
        "implementation",
        "end.");


    $fh->WriteLn();
    $fh->Close();
}

#-------------------------------------------------------------------------------
# Function        : BuildVersionVB
#
# Description     : Create a VB6 file in Basic format
#
# Inputs          : $FileName       - Output filename (Optional)
#                   $Prefix         - Tag for all generated definitions
#
#
# Returns         : 
#
sub BuildVersionVB
{
    my ( $fname, $Prefix ) = @_;

    #
    #   Default name of the file
    #
    $fname = 'version.bas' unless $fname;
    $fname .= '.bas'
        unless ( $fname =~ m~\.~ );

    #
    #   Store the files location for use at runtime
    #   It will be a file that is 'known' to JATS
    #
    $fname = ::BuildAddKnownFile ( $Srcdir, $fname );
    return if ( $Clobber );      # clobber mode ?
    Message ("Creating Visual Basic Version File: $fname" );

    #
    #   Generate version source file
    #   This file contains ONLY constant definitions.

    #
    #   Allow for a user supplied property prefix
    #   Not really needed as
    #
    my $vtag = '';
    $vtag = $Prefix . '_' if $Prefix;


    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersionClean($BUILDNAME_VERSION);
    my @PACKAGEVERS = PackageEntry::GetPackageVersionList();

    #
    #   Create properties in the same form as for "C" definitions
    #   Note:
    #       The 'ALL' is in a format used by other software. Do not change
    #
    sub pvbstring
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return sprintf ( "Public Const %-24s = \"%s\"" , $arg, $val);
    }
    sub pvbnum
    {
        my ($arg, $val) = @_;
        Error ("Undefined value for $arg") unless ( defined $val );
        return sprintf ( "Public Const %-24s = %s" , $arg, $val );
    }

    my $fh = ConfigurationFile::New( $fname, '--Type=Basic' );
    $fh->HeaderSimple( "buildlib (Version $BuildVersion)",
                       "Visual Basic Version Definition" );

    $fh->WriteLn(
        "Attribute VB_Name = \"JatsVersion\"",
        '',
        pvbstring ("${vtag}BUILDNAME",      $BUILDNAME),
        pvbstring ("${vtag}BUILDDATE",      $::CurrentTime),
        '',
        pvbstring ("${vtag}PACKAGE",        $BUILDNAME_PACKAGE),
        pvbstring ("${vtag}VERSION",        $BUILDNAME_VERSION),
        pvbstring ("${vtag}MAJOR_STR",      $major),
        pvbstring ("${vtag}MINOR_STR",      $minor),
        pvbstring ("${vtag}PATCH_STR",      $patch),
        pvbstring ("${vtag}BUILD_STR",      $build),
        pvbstring ("${vtag}PATCHBUILD_STR", $raw_patch),
        pvbstring ("${vtag}PROJECT",        $BUILDNAME_PROJECT),
        pvbnum    ("${vtag}MAJOR",          $major),
        pvbnum    ("${vtag}MINOR",          $minor),
        pvbnum    ("${vtag}PATCH",          $patch),
        pvbnum    ("${vtag}BUILD",          $build),
        pvbnum    ("${vtag}PATCHBUILD",     $raw_patch),
        pvbstring ("${vtag}ALL",            "$BUILDNAME_PACKAGE ($BUILDNAME_VERSION.$BUILDNAME_PROJECT) @PACKAGEVERS"),
        pvbnum    ("${vtag}BUILDTIME",      strip_zeros(time())),
        ''
        );

    #
    #   Create a set of definitions for each dependent package
    #
    $fh->Comment("Dependent Packages and Versions\n");
    $fh->Comment("\n");

    foreach my $tag ( PackageEntry::GetPackageList() )
    {
        my ($name, $version, $type) = PackageEntry::GetPackageData($tag);
        $fh->WriteLn(pvbstring ("${vtag}PACKAGE_$name", $version));
    }

    $fh->WriteLn();
    $fh->Close();
}

#-------------------------------------------------------------------------------
# Function        : SplitVersionClean
#
# Description     : Pull apart the Version Number and clean it up
#                   Remove leading zeros from components
#
# Inputs          : $version    - Version Number
#
# Returns         : A list of:
#                       Major, Minor, Patch, Build, RawPatch
#                   with leading zeros removed
#
sub SplitVersionClean
{
    my ($version) = @_;
    my ($major, $minor, $patch, $build, $raw_patch) = SplitVersion($version);

    return (
        strip_zeros($major),
        strip_zeros($minor),
        strip_zeros($patch),
        strip_zeros($build),
        strip_zeros($raw_patch)
    );
}

#-------------------------------------------------------------------------------
# Function        : stip_zeros
#
# Description     : Remove leading 0's from a string
#
# Inputs          : A string
#
# Returns         : A string without leading zeros
#
sub strip_zeros
{
    my ($text) = @_;

    $text =~ s~^0*~~;
    $text = '0' unless ( $text );
    return $text;
}
 
1;