###########################################################################
#                                  _   _ ____  _
#  Project                     ___| | | |  _ \| |
#                             / __| | | | |_) | |
#                            | (__| |_| |  _ <| |___
#                             \___|\___/|_| \_\_____|
#
# Copyright (C) Evgeny Grin (Karlson2k), <k2k@narod.ru>.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at https://curl.se/docs/copyright.html.
#
# You may opt to use, copy, modify, merge, publish, distribute and/or sell
# copies of the Software, and permit persons to whom the Software is
# furnished to do so, under the terms of the COPYING file.
#
# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
# KIND, either express or implied.
#
# SPDX-License-Identifier: curl
#
###########################################################################

# This Perl package helps with path transforming when running curl tests on
# native Windows and MSYS/Cygwin.
# Following input formats are supported (via built-in Perl functions):
#  (1) /some/path   - absolute path in POSIX-style
#  (2) D:/some/path - absolute path in Windows-style
#  (3) some/path    - relative path
#  (4) D:some/path  - path relative to current directory on Windows drive
#                     (paths like 'D:' are treated as 'D:./') (*)
#  (5) \some/path   - path from root directory on current Windows drive (*)
# All forward '/' and back '\' slashes are treated identically except leading
# slash in forms (1) and (5).
# Forward slashes are simpler processed in Perl, do not require extra escaping
# for shell (unlike back slashes) and accepted by Windows native programs, so
# all functions return paths with only forward slashes.
# All returned paths don't contain any duplicated slashes, only single slashes
# are used as directory separators on output.
# On non-Windows platforms functions acts as transparent wrappers for similar
# Perl's functions or return unmodified string (depending on functionality),
# so all functions can be unconditionally used on all platforms.
#
# (*) CAUTION! Forms (4) and (5) are not recommended to use as they can be
#     interpreted incorrectly in Perl and MSYS/Cygwin environment have low
#     control on Windows current drive and Windows current path on specific
#     drive.

__all__ = ('os_is_win', 'exe_ext',
           'sys_native_abs_path', 'sys_native_current_path',
           'build_sys_abs_path')

use Cwd 'abs_path';


# Cached static variable, Perl 5.0-compatible.
is_win: bool

def os_is_win() -> bool:
    # Returns boolean True if OS is any form of Windows.
    global is_win
    if not defined is_win:
    is_win = ($^O == "MSWin32" or
              $^O == "cygwin"  or
              $^O == "msys")
    return is_win


# Cached static variable, Perl 5.0-compatible.
cygdrive_present: bool

def drives_mounted_on_cygdrive() -> bool:
    # Returns boolean True if Windows drives mounted with "/cygdrive/" prefix.
    global cygdrive_present
    if not defined $cygdrive_present:
        cygdrive_present = ((-e "/cygdrive/") and (-d "/cygdrive/"))
    return cygdrive_present


def sys_native_current_path():
    # Returns current working directory in Windows format on Windows.
    if not os_is_win():
        return Cwd::getcwd()
    else:
        if $^O == "MSWin32":
            cur_dir = Cwd::getcwd()
        else:
            cur_dir = Cygwin::posix_to_win_path(Cwd::getcwd())
        cur_dir =~ s{[/\\]+}{/}g;
        return cur_dir


def sys_native_abs_path($path):
    # Converts given path to system native absolute path, i.e. to Windows
    # absolute format on Windows platform. Both relative and absolute
    # formats are supported for input.
    if not os_is_win():
        # Return untouched on non-Windows platforms.
        return Cwd::abs_path($path)
    else:
        # Do not process empty path.
        if $path == "":
            return $path
        else:
            if ($^O == "msys" or
                $^O == "cygwin"):
                res = Cygwin::posix_to_win_path(Cwd::abs_path($path))
            elif $path =~ m{^/(cygdrive/)?([a-z])/(.*)}:
                res = $2.upper() + ":/" + $3
            else:
                res = Cwd::abs_path($path)
            res =~ s{[/\\]+}{/}g;
            return res


def build_sys_abs_path($path):
    # Converts given path to build system format absolute path, i.e. to
    # MSYS/Cygwin POSIX-style absolute format on Windows platform. Both
    # relative and absolute formats are supported for input.
    if not os_is_win():
        # Return untouched on non-Windows platforms.
        return Cwd::abs_path($path)
    elif ($^O == "msys" or
          $^O == "cygwin"):
        return Cygwin::win_to_posix_path($path, 1)
    else:
        res = Cwd::abs_path($path);
        if res =~ m{^([A-Za-z]):(.*)}:
            res = "/" + lc($1) + $2
            if drives_mounted_on_cygdrive():
                res = "/cygdrive" + res
        return res


def exe_ext(component: str) -> str:
    # Return file extension for executable files on this operating system
    if ("CURL_TEST_EXE_EXT_" + component) in os.environ:
        return os.environ["CURL_TEST_EXE_EXT_" + component]
    elif "CURL_TEST_EXE_EXT" in os.environ:
        return os.environ["CURL_TEST_EXE_EXT"]
    elif ($^O == "MSWin32" or
          $^O == "cygwin"  or
          $^O == "msys"    or
          $^O == "dos"     or
          $^O == "os2"):
          return ".exe"
    else:
        return ""
