#!/usr/bin/env perl
# Generate main file, individual apps and solution files for
# MS Visual Studio 2017
#
# Must be run from Mbed TLS root or scripts directory.
# Takes no argument.
#
# Copyright The Mbed TLS Contributors
# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
use warnings;
use strict;
use Digest::MD5 'md5_hex';
my $vsx_dir = "visualc/VS2017";
my $vsx_ext = "vcxproj";
my $vsx_app_tpl_file = "scripts/data_files/vs2017-app-template.$vsx_ext";
my $vsx_main_tpl_file = "scripts/data_files/vs2017-main-template.$vsx_ext";
my $vsx_main_file = "$vsx_dir/mbedTLS.$vsx_ext";
my $vsx_sln_tpl_file = "scripts/data_files/vs2017-sln-template.sln";
my $vsx_sln_file = "$vsx_dir/mbedTLS.sln";
my $mbedtls_programs_dir = "programs";
my $tfpsacrypto_programs_dir = "tf-psa-crypto/programs";
my $mbedtls_header_dir = 'include/mbedtls';
my $drivers_builtin_header_dir = 'tf-psa-crypto/drivers/builtin/include/mbedtls';
my $psa_header_dir = 'tf-psa-crypto/include/psa';
my $tls_source_dir = 'library';
my $crypto_core_source_dir = 'tf-psa-crypto/core';
my $crypto_source_dir = 'tf-psa-crypto/drivers/builtin/src';
my $tls_test_source_dir = 'tests/src';
my $tls_test_header_dir = 'tests/include/test';
my $test_source_dir = 'framework/tests/src';
my $test_header_dir = 'framework/tests/include/test';
my $test_drivers_header_dir = 'framework/tests/include/test/drivers';
my $test_drivers_source_dir = 'framework/tests/src/drivers';
my @thirdparty_header_dirs = qw(
    tf-psa-crypto/drivers/everest/include/everest
);
my @thirdparty_source_dirs = qw(
    tf-psa-crypto/drivers/everest/library
    tf-psa-crypto/drivers/everest/library/kremlib
    tf-psa-crypto/drivers/everest/library/legacy
);
# Directories to add to the include path.
# Order matters in case there are files with the same name in more than
# one directory: the compiler will use the first match.
my @include_directories = qw(
    include
    tf-psa-crypto/include
    tf-psa-crypto/drivers/builtin/include
    tf-psa-crypto/drivers/everest/include/
    tf-psa-crypto/drivers/everest/include/everest
    tf-psa-crypto/drivers/everest/include/everest/vs2013
    tf-psa-crypto/drivers/everest/include/everest/kremlib
    tests/include
    framework/tests/include
);
my $include_directories = join(';', map {"../../$_"} @include_directories);
# Directories to add to the include path when building the libraries, but not
# when building tests or applications.
my @library_include_directories = qw(
    library
    tf-psa-crypto/core
    tf-psa-crypto/drivers/builtin/src
);
my $library_include_directories =
  join(';', map {"../../$_"} (@library_include_directories,
                              @include_directories));
my @excluded_files = qw(
    tf-psa-crypto/drivers/everest/library/Hacl_Curve25519.c
);
my %excluded_files = ();
foreach (@excluded_files) { $excluded_files{$_} = 1 }
my $vsx_hdr_tpl = <
EOT
my $vsx_src_tpl = <
EOT
my $vsx_sln_app_entry_tpl = <;
    close $fh;
    return $content;
}
sub content_to_file {
    my ($content, $filename) = @_;
    open my $fh, '>:crlf', $filename or die "Could not write to $filename\n";
    print $fh $content;
    close $fh;
}
sub gen_app_guid {
    my ($path) = @_;
    my $guid = md5_hex( "mbedTLS:$path" );
    $guid =~ s/(.{8})(.{4})(.{4})(.{4})(.{12})/\U{$1-$2-$3-$4-$5}/;
    return $guid;
}
sub gen_app {
    my ($path, $template, $dir, $ext) = @_;
    my $guid = gen_app_guid( $path );
    $path =~ s!/!\\!g;
    (my $appname = $path) =~ s/.*\\//;
    my $is_test_app = ($path =~ m/^test\\/);
    my $srcs = "";
    if( $appname eq "ssl_client2" or $appname eq "ssl_server2" or
        $appname eq "query_compile_time_config" ) {
        $srcs .= "\n    ";
    }
    if( $appname eq "ssl_client2" or $appname eq "ssl_server2" ) {
        $srcs .= "\n    ";
    }
    my $content = $template;
    $content =~ s//$srcs/g;
    $content =~ s//$appname/g;
    $content =~ s//$guid/g;
    $content =~ s/INCLUDE_DIRECTORIES\n/($is_test_app ?
                                         $library_include_directories :
                                         $include_directories)/ge;
    content_to_file( $content, "$dir/$appname.$ext" );
}
sub get_app_list {
    my $makefile_contents = slurp_file('programs/Makefile');
    $makefile_contents =~ /\n\s*APPS\s*=[\\\s]*(.*?)(? } @header_dirs);
    my @source_dirs = (
                       $tls_source_dir,
                       $crypto_core_source_dir,
                       $crypto_source_dir,
                       $test_source_dir,
                       $tls_test_source_dir,
                       $test_drivers_source_dir,
                       @thirdparty_source_dirs,
                      );
    my @sources = (map { <$_/*.c> } @source_dirs);
    @headers = grep { ! $excluded_files{$_} } @headers;
    @sources = grep { ! $excluded_files{$_} } @sources;
    map { s!/!\\!g } @headers;
    map { s!/!\\!g } @sources;
    gen_app_files( @app_list );
    gen_main_file( \@headers, \@sources,
                   $vsx_hdr_tpl, $vsx_src_tpl,
                   $vsx_main_tpl_file, $vsx_main_file );
    gen_vsx_solution( @app_list );
    return 0;
}