Annotation of embedaddon/curl/tests/pathhelp.pm, revision 1.1
1.1 ! misho 1: ###########################################################################
! 2: # _ _ ____ _
! 3: # Project ___| | | | _ \| |
! 4: # / __| | | | |_) | |
! 5: # | (__| |_| | _ <| |___
! 6: # \___|\___/|_| \_\_____|
! 7: #
! 8: # Copyright (C) 2016 - 2020, Evgeny Grin (Karlson2k), <k2k@narod.ru>.
! 9: #
! 10: # This software is licensed as described in the file COPYING, which
! 11: # you should have received as part of this distribution. The terms
! 12: # are also available at https://curl.haxx.se/docs/copyright.html.
! 13: #
! 14: # You may opt to use, copy, modify, merge, publish, distribute and/or sell
! 15: # copies of the Software, and permit persons to whom the Software is
! 16: # furnished to do so, under the terms of the COPYING file.
! 17: #
! 18: # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
! 19: # KIND, either express or implied.
! 20: #
! 21: ###########################################################################
! 22:
! 23: # This Perl package helps with path transforming when running curl tests on
! 24: # Win32 platform with Msys or Cygwin.
! 25: # Three main functions 'sys_native_abs_path', 'sys_native_path' and
! 26: # 'build_sys_abs_path' autodetect format of given pathnames. Following formats
! 27: # are supported:
! 28: # (1) /some/path - absolute path in Unix-style
! 29: # (2) D:/some/path - absolute path in Win32-style
! 30: # (3) some/path - relative path
! 31: # (4) D:some/path - path relative to current directory on Win32 drive (paths
! 32: # like 'D:' are treated as 'D:./') (*)
! 33: # (5) \some/path - path from root directory on current Win32 drive (*)
! 34: # All forward '/' and back '\' slashes are treated identically except leading
! 35: # slash in forms (1) and (5).
! 36: # Forward slashes are simpler processed in Perl, do not require extra escaping
! 37: # for shell (unlike back slashes) and accepted by Win32 native programs, so
! 38: # all functions return paths with only forward slashes except
! 39: # 'sys_native_path' which returns paths with first forward slash for form (5).
! 40: # All returned paths don't contain any duplicated slashes, only single slashes
! 41: # are used as directory separators on output.
! 42: # On non-Windows platforms functions acts as transparent wrappers for similar
! 43: # Perl's functions or return unmodified string (depending on functionality),
! 44: # so all functions can be unconditionally used on all platforms.
! 45: #
! 46: # (*) CAUTION! Forms (4) and (5) are not recommended to use as they can be
! 47: # interpreted incorrectly in Perl and Msys/Cygwin environment have low
! 48: # control on Win32 current drive and Win32 current path on specific drive.
! 49:
! 50:
! 51: package pathhelp;
! 52: use strict;
! 53: use warnings;
! 54: use Cwd 'abs_path';
! 55:
! 56: BEGIN {
! 57: require Exporter;
! 58:
! 59: our @ISA = qw(Exporter);
! 60:
! 61: our @EXPORT = qw(
! 62: sys_native_abs_path
! 63: sys_native_path
! 64: );
! 65:
! 66: our @EXPORT_OK = qw(
! 67: build_sys_abs_path
! 68: sys_native_current_path
! 69: normalize_path
! 70: os_is_win
! 71: $use_cygpath
! 72: should_use_cygpath
! 73: drives_mounted_on_cygdrive
! 74: );
! 75: }
! 76:
! 77:
! 78: #######################################################################
! 79: # Block for cached static variables
! 80: #
! 81: {
! 82: # Cached static variable, Perl 5.0-compatible.
! 83: my $is_win = $^O eq 'MSWin32'
! 84: || $^O eq 'cygwin'
! 85: || $^O eq 'msys';
! 86:
! 87: # Returns boolean true if OS is any form of Windows.
! 88: sub os_is_win {
! 89: return $is_win;
! 90: }
! 91:
! 92: # Cached static variable, Perl 5.0-compatible.
! 93: my $cygdrive_present;
! 94:
! 95: # Returns boolean true if Win32 drives mounted with '/cygdrive/' prefix.
! 96: sub drives_mounted_on_cygdrive {
! 97: return $cygdrive_present if defined $cygdrive_present;
! 98: $cygdrive_present = ((-e '/cygdrive/') && (-d '/cygdrive/')) ? 1 : 0;
! 99: return $cygdrive_present;
! 100: }
! 101: }
! 102:
! 103: our $use_cygpath; # Only for Win32:
! 104: # undef - autodetect
! 105: # 1 - use cygpath
! 106: # 0 - do not use cygpath
! 107:
! 108: # Returns boolean true if 'cygpath' utility should be used for path conversion.
! 109: sub should_use_cygpath {
! 110: unless (os_is_win()) {
! 111: $use_cygpath = 0;
! 112: return 0;
! 113: }
! 114: return $use_cygpath if defined $use_cygpath;
! 115:
! 116: $use_cygpath = (qx{cygpath -u '.\\' 2>/dev/null} eq "./\n" && $? == 0);
! 117:
! 118: return $use_cygpath;
! 119: }
! 120:
! 121: #######################################################################
! 122: # Performs path "normalization": all slashes converted to forward
! 123: # slashes (except leading slash), all duplicated slashes are replaced
! 124: # with single slashes, all relative directories ('./' and '../') are
! 125: # resolved if possible.
! 126: # Path processed as string, directories are not checked for presence so
! 127: # path for not yet existing directory can be "normalized".
! 128: #
! 129: sub normalize_path;
! 130:
! 131: #######################################################################
! 132: # Returns current working directory in Win32 format on Windows.
! 133: #
! 134: sub sys_native_current_path {
! 135: return Cwd::getcwd() unless os_is_win();
! 136:
! 137: my $cur_dir;
! 138: if($^O eq 'msys') {
! 139: # MSys shell has built-in command.
! 140: chomp($cur_dir = `bash -c 'pwd -W'`);
! 141: if($? != 0) {
! 142: warn "Can't determine Win32 current directory.\n";
! 143: return undef;
! 144: }
! 145: # Add final slash if required.
! 146: $cur_dir .= '/' if length($cur_dir) > 3;
! 147: }
! 148: else {
! 149: # Do not use 'cygpath' - it falsely succeed on paths like '/cygdrive'.
! 150: $cur_dir = `cmd "/c;" echo %__CD__%`;
! 151: if($? != 0 || substr($cur_dir, 0, 1) eq '%') {
! 152: warn "Can't determine Win32 current directory.\n";
! 153: return undef;
! 154: }
! 155: # Remove both '\r' and '\n'.
! 156: $cur_dir =~ s{\n|\r}{}g;
! 157:
! 158: # Replace back slashes with forward slashes.
! 159: $cur_dir =~ s{\\}{/}g;
! 160: }
! 161: return $cur_dir;
! 162: }
! 163:
! 164: #######################################################################
! 165: # Returns Win32 current drive letter with colon.
! 166: #
! 167: sub get_win32_current_drive {
! 168: # Notice parameter "/c;" - it's required to turn off Msys's
! 169: # transformation of '/c' and compatible with Cygwin.
! 170: my $drive_letter = `cmd "/c;" echo %__CD__:~0,2%`;
! 171: if($? != 0 || substr($drive_letter, 1, 1) ne ':') {
! 172: warn "Can't determine current Win32 drive letter.\n";
! 173: return undef;
! 174: }
! 175:
! 176: return substr($drive_letter, 0, 2);
! 177: }
! 178:
! 179: # Internal function. Converts path by using Msys's built-in transformation.
! 180: # Returned path may contain duplicated and back slashes.
! 181: sub do_msys_transform;
! 182:
! 183: # Internal function. Gets two parameters: first parameter must be single
! 184: # drive letter ('c'), second optional parameter is path relative to drive's
! 185: # current working directory. Returns Win32 absolute normalized path.
! 186: sub get_abs_path_on_win32_drive;
! 187:
! 188: # Internal function. Tries to find or guess Win32 version of given
! 189: # absolute Unix-style path. Other types of paths are not supported.
! 190: # Returned paths contain only single forward slashes (no back and
! 191: # duplicated slashes).
! 192: # Last resort. Used only when other transformations are not available.
! 193: sub do_dumb_guessed_transform;
! 194:
! 195: #######################################################################
! 196: # Converts given path to system native format, i.e. to Win32 format on
! 197: # Windows platform. Relative paths converted to relative, absolute
! 198: # paths converted to absolute.
! 199: #
! 200: sub sys_native_path {
! 201: my ($path) = @_;
! 202:
! 203: # Return untouched on non-Windows platforms.
! 204: return $path unless (os_is_win());
! 205:
! 206: # Do not process empty path.
! 207: return $path if ($path eq '');
! 208:
! 209: if($path =~ s{^([a-zA-Z]):$}{\u$1:}) {
! 210: # Path is single drive with colon. (C:)
! 211: # This type of paths is not processed correctly by 'cygpath'.
! 212: # WARNING!
! 213: # Be careful, this relative path can be accidentally transformed
! 214: # into wrong absolute path by adding to it some '/dirname' with
! 215: # slash at font.
! 216: return $path;
! 217: }
! 218: elsif($path =~ m{^\\} || $path =~ m{^[a-zA-Z]:[^/\\]}) {
! 219: # Path is a directory or filename on Win32 current drive or relative
! 220: # path on current directory on specific Win32 drive.
! 221: # ('\path' or 'D:path')
! 222: # First type of paths is not processed by Msys transformation and
! 223: # resolved to absolute path by 'cygpath'.
! 224: # Second type is not processed by Msys transformation and may be
! 225: # incorrectly processed by 'cygpath' (for paths like 'D:..\../.\')
! 226:
! 227: my $first_char = ucfirst(substr($path, 0, 1));
! 228:
! 229: # Replace any back and duplicated slashes with single forward slashes.
! 230: $path =~ s{[\\/]+}{/}g;
! 231:
! 232: # Convert leading slash back to forward slash to indicate
! 233: # directory on Win32 current drive or capitalize drive letter.
! 234: substr($path, 0, 1) = $first_char;
! 235: return $path;
! 236: }
! 237: elsif(should_use_cygpath()) {
! 238: # 'cygpath' is available - use it.
! 239:
! 240: # Remove leading duplicated forward and back slashes, as they may
! 241: # prevent transforming and may be not processed.
! 242: $path =~ s{^([\\/])[\\/]+}{$1}g;
! 243:
! 244: my $has_final_slash = ($path =~ m{[/\\]$});
! 245:
! 246: # Use 'cygpath', '-m' means Win32 path with forward slashes.
! 247: chomp($path = `cygpath -m '$path'`);
! 248: if ($? != 0) {
! 249: warn "Can't convert path by \"cygpath\".\n";
! 250: return undef;
! 251: }
! 252:
! 253: # 'cygpath' may remove last slash for existing directories.
! 254: $path .= '/' if($has_final_slash);
! 255:
! 256: # Remove any duplicated forward slashes (added by 'cygpath' for root
! 257: # directories)
! 258: $path =~ s{//+}{/}g;
! 259:
! 260: return $path;
! 261: }
! 262: elsif($^O eq 'msys') {
! 263: # Msys transforms automatically path to Windows native form in staring
! 264: # program parameters if program is not Msys-based.
! 265:
! 266: $path = do_msys_transform($path);
! 267: return undef unless defined $path;
! 268:
! 269: # Capitalize drive letter for Win32 paths.
! 270: $path =~ s{^([a-z]:)}{\u$1};
! 271:
! 272: # Replace any back and duplicated slashes with single forward slashes.
! 273: $path =~ s{[\\/]+}{/}g;
! 274: return $path;
! 275: }
! 276: elsif($path =~ s{^([a-zA-Z]):[/\\]}{\u$1:/}) {
! 277: # Path is already in Win32 form. ('C:\path')
! 278:
! 279: # Replace any back and duplicated slashes with single forward slashes.
! 280: $path =~ s{[\\/]+}{/}g;
! 281: return $path;
! 282: }
! 283: elsif($path !~ m{^/}) {
! 284: # Path is in relative form. ('path/name', './path' or '../path')
! 285:
! 286: # Replace any back and duplicated slashes with single forward slashes.
! 287: $path =~ s{[\\/]+}{/}g;
! 288: return $path;
! 289: }
! 290:
! 291: # OS is Windows, but not Msys, path is absolute, path is not in Win32
! 292: # form and 'cygpath' is not available.
! 293: return do_dumb_guessed_transform($path);
! 294: }
! 295:
! 296: #######################################################################
! 297: # Converts given path to system native absolute path, i.e. to Win32
! 298: # absolute format on Windows platform. Both relative and absolute
! 299: # formats are supported for input.
! 300: #
! 301: sub sys_native_abs_path {
! 302: my ($path) = @_;
! 303:
! 304: unless(os_is_win()) {
! 305: # Convert path to absolute form.
! 306: $path = Cwd::abs_path($path);
! 307:
! 308: # Do not process further on non-Windows platforms.
! 309: return $path;
! 310: }
! 311:
! 312: if($path =~ m{^([a-zA-Z]):($|[^/\\].*$)}) {
! 313: # Path is single drive with colon or relative path on Win32 drive.
! 314: # ('C:' or 'C:path')
! 315: # This kind of relative path is not processed correctly by 'cygpath'.
! 316: # Get specified drive letter
! 317: return get_abs_path_on_win32_drive($1, $2);
! 318: }
! 319: elsif($path eq '') {
! 320: # Path is empty string. Return current directory.
! 321: # Empty string processed correctly by 'cygpath'.
! 322:
! 323: return sys_native_current_path();
! 324: }
! 325: elsif(should_use_cygpath()) {
! 326: # 'cygpath' is available - use it.
! 327:
! 328: my $has_final_slash = ($path =~ m{[\\/]$});
! 329:
! 330: # Remove leading duplicated forward and back slashes, as they may
! 331: # prevent transforming and may be not processed.
! 332: $path =~ s{^([\\/])[\\/]+}{$1}g;
! 333:
! 334: print "Inter result: \"$path\"\n";
! 335: # Use 'cygpath', '-m' means Win32 path with forward slashes,
! 336: # '-a' means absolute path
! 337: chomp($path = `cygpath -m -a '$path'`);
! 338: if($? != 0) {
! 339: warn "Can't resolve path by usung \"cygpath\".\n";
! 340: return undef;
! 341: }
! 342:
! 343: # 'cygpath' may remove last slash for existing directories.
! 344: $path .= '/' if($has_final_slash);
! 345:
! 346: # Remove any duplicated forward slashes (added by 'cygpath' for root
! 347: # directories)
! 348: $path =~ s{//+}{/}g;
! 349:
! 350: return $path
! 351: }
! 352: elsif($path =~ s{^([a-zA-Z]):[/\\]}{\u$1:/}) {
! 353: # Path is already in Win32 form. ('C:\path')
! 354:
! 355: # Replace any possible back slashes with forward slashes,
! 356: # remove any duplicated slashes, resolve relative dirs.
! 357: return normalize_path($path);
! 358: }
! 359: elsif(substr($path, 0, 1) eq '\\' ) {
! 360: # Path is directory or filename on Win32 current drive. ('\Windows')
! 361:
! 362: my $w32drive = get_win32_current_drive();
! 363: return undef unless defined $w32drive;
! 364:
! 365: # Combine drive and path.
! 366: # Replace any possible back slashes with forward slashes,
! 367: # remove any duplicated slashes, resolve relative dirs.
! 368: return normalize_path($w32drive . $path);
! 369: }
! 370:
! 371: unless (substr($path, 0, 1) eq '/') {
! 372: # Path is in relative form. Resolve relative directories in Unix form
! 373: # *BEFORE* converting to Win32 form otherwise paths like
! 374: # '../../../cygdrive/c/windows' will not be resolved.
! 375: my $cur_dir = `pwd -L`;
! 376: if($? != 0) {
! 377: warn "Can't determine current working directory.\n";
! 378: return undef;
! 379: }
! 380: chomp($cur_dir);
! 381:
! 382: $path = $cur_dir . '/' . $path;
! 383: }
! 384:
! 385: # Resolve relative dirs.
! 386: $path = normalize_path($path);
! 387: return undef unless defined $path;
! 388:
! 389: if($^O eq 'msys') {
! 390: # Msys transforms automatically path to Windows native form in staring
! 391: # program parameters if program is not Msys-based.
! 392: $path = do_msys_transform($path);
! 393: return undef unless defined $path;
! 394:
! 395: # Replace any back and duplicated slashes with single forward slashes.
! 396: $path =~ s{[\\/]+}{/}g;
! 397: return $path;
! 398: }
! 399: # OS is Windows, but not Msys, path is absolute, path is not in Win32
! 400: # form and 'cygpath' is not available.
! 401:
! 402: return do_dumb_guessed_transform($path);
! 403: }
! 404:
! 405: # Internal function. Converts given Unix-style absolute path to Win32 format.
! 406: sub simple_transform_win32_to_unix;
! 407:
! 408: #######################################################################
! 409: # Converts given path to build system format absolute path, i.e. to
! 410: # Msys/Cygwin Unix-style absolute format on Windows platform. Both
! 411: # relative and absolute formats are supported for input.
! 412: #
! 413: sub build_sys_abs_path {
! 414: my ($path) = @_;
! 415:
! 416: unless(os_is_win()) {
! 417: # Convert path to absolute form.
! 418: $path = Cwd::abs_path($path);
! 419:
! 420: # Do not process further on non-Windows platforms.
! 421: return $path;
! 422: }
! 423:
! 424: if($path =~ m{^([a-zA-Z]):($|[^/\\].*$)}) {
! 425: # Path is single drive with colon or relative path on Win32 drive.
! 426: # ('C:' or 'C:path')
! 427: # This kind of relative path is not processed correctly by 'cygpath'.
! 428: # Get specified drive letter
! 429:
! 430: # Resolve relative dirs in Win32-style path or paths like 'D:/../c/'
! 431: # will be resolved incorrectly.
! 432: # Replace any possible back slashes with forward slashes,
! 433: # remove any duplicated slashes.
! 434: $path = get_abs_path_on_win32_drive($1, $2);
! 435: return undef unless defined $path;
! 436:
! 437: return simple_transform_win32_to_unix($path);
! 438: }
! 439: elsif($path eq '') {
! 440: # Path is empty string. Return current directory.
! 441: # Empty string processed correctly by 'cygpath'.
! 442:
! 443: chomp($path = `pwd -L`);
! 444: if($? != 0) {
! 445: warn "Can't determine Unix-style current working directory.\n";
! 446: return undef;
! 447: }
! 448:
! 449: # Add final slash if not at root dir.
! 450: $path .= '/' if length($path) > 2;
! 451: return $path;
! 452: }
! 453: elsif(should_use_cygpath()) {
! 454: # 'cygpath' is available - use it.
! 455:
! 456: my $has_final_slash = ($path =~ m{[\\/]$});
! 457:
! 458: # Resolve relative directories, as they may be not resolved for
! 459: # Unix-style paths.
! 460: # Remove duplicated slashes, as they may be not processed.
! 461: $path = normalize_path($path);
! 462: return undef unless defined $path;
! 463:
! 464: # Use 'cygpath', '-u' means Unix-stile path,
! 465: # '-a' means absolute path
! 466: chomp($path = `cygpath -u -a '$path'`);
! 467: if($? != 0) {
! 468: warn "Can't resolve path by usung \"cygpath\".\n";
! 469: return undef;
! 470: }
! 471:
! 472: # 'cygpath' removes last slash if path is root dir on Win32 drive.
! 473: # Restore it.
! 474: $path .= '/' if($has_final_slash &&
! 475: substr($path, length($path) - 1, 1) ne '/');
! 476:
! 477: return $path
! 478: }
! 479: elsif($path =~ m{^[a-zA-Z]:[/\\]}) {
! 480: # Path is already in Win32 form. ('C:\path')
! 481:
! 482: # Resolve relative dirs in Win32-style path otherwise paths
! 483: # like 'D:/../c/' will be resolved incorrectly.
! 484: # Replace any possible back slashes with forward slashes,
! 485: # remove any duplicated slashes.
! 486: $path = normalize_path($path);
! 487: return undef unless defined $path;
! 488:
! 489: return simple_transform_win32_to_unix($path);
! 490: }
! 491: elsif(substr($path, 0, 1) eq '\\') {
! 492: # Path is directory or filename on Win32 current drive. ('\Windows')
! 493:
! 494: my $w32drive = get_win32_current_drive();
! 495: return undef unless defined $w32drive;
! 496:
! 497: # Combine drive and path.
! 498: # Resolve relative dirs in Win32-style path or paths like 'D:/../c/'
! 499: # will be resolved incorrectly.
! 500: # Replace any possible back slashes with forward slashes,
! 501: # remove any duplicated slashes.
! 502: $path = normalize_path($w32drive . $path);
! 503: return undef unless defined $path;
! 504:
! 505: return simple_transform_win32_to_unix($path);
! 506: }
! 507:
! 508: # Path is not in any Win32 form.
! 509: unless (substr($path, 0, 1) eq '/') {
! 510: # Path in relative form. Resolve relative directories in Unix form
! 511: # *BEFORE* converting to Win32 form otherwise paths like
! 512: # '../../../cygdrive/c/windows' will not be resolved.
! 513: my $cur_dir = `pwd -L`;
! 514: if($? != 0) {
! 515: warn "Can't determine current working directory.\n";
! 516: return undef;
! 517: }
! 518: chomp($cur_dir);
! 519:
! 520: $path = $cur_dir . '/' . $path;
! 521: }
! 522:
! 523: return normalize_path($path);
! 524: }
! 525:
! 526: #######################################################################
! 527: # Performs path "normalization": all slashes converted to forward
! 528: # slashes (except leading slash), all duplicated slashes are replaced
! 529: # with single slashes, all relative directories ('./' and '../') are
! 530: # resolved if possible.
! 531: # Path processed as string, directories are not checked for presence so
! 532: # path for not yet existing directory can be "normalized".
! 533: #
! 534: sub normalize_path {
! 535: my ($path) = @_;
! 536:
! 537: # Don't process empty paths.
! 538: return $path if $path eq '';
! 539:
! 540: unless($path =~ m{(?:^|\\|/)\.{1,2}(?:\\|/|$)}) {
! 541: # Speed up processing of simple paths.
! 542: my $first_char = substr($path, 0, 1);
! 543: $path =~ s{[\\/]+}{/}g;
! 544: # Restore starting backslash if any.
! 545: substr($path, 0, 1) = $first_char;
! 546: return $path;
! 547: }
! 548:
! 549: my @arr;
! 550: my $prefix;
! 551: my $have_root = 0;
! 552:
! 553: # Check whether path starts from Win32 drive. ('C:path' or 'C:\path')
! 554: if($path =~ m{^([a-zA-Z]:(/|\\)?)(.*$)}) {
! 555: $prefix = $1;
! 556: $have_root = 1 if defined $2;
! 557: # Process path separately from drive letter.
! 558: @arr = split(m{\/|\\}, $3);
! 559: # Replace backslash with forward slash if required.
! 560: substr($prefix, 2, 1) = '/' if $have_root;
! 561: }
! 562: else {
! 563: if($path =~ m{^(\/|\\)}) {
! 564: $have_root = 1;
! 565: $prefix = $1;
! 566: }
! 567: else {
! 568: $prefix = '';
! 569: }
! 570: @arr = split(m{\/|\\}, $path);
! 571: }
! 572:
! 573: my $p = 0;
! 574: my @res;
! 575:
! 576: for my $el (@arr) {
! 577: if(length($el) == 0 || $el eq '.') {
! 578: next;
! 579: }
! 580: elsif($el eq '..' && @res > 0 && $res[$#res] ne '..') {
! 581: pop @res;
! 582: next;
! 583: }
! 584: push @res, $el;
! 585: }
! 586: if($have_root && @res > 0 && $res[0] eq '..') {
! 587: warn "Error processing path \"$path\": " .
! 588: "Parent directory of root directory does not exist!\n";
! 589: return undef;
! 590: }
! 591:
! 592: my $ret = $prefix . join('/', @res);
! 593: $ret .= '/' if($path =~ m{\\$|/$} && scalar @res > 0);
! 594:
! 595: return $ret;
! 596: }
! 597:
! 598: # Internal function. Converts path by using Msys's built-in
! 599: # transformation.
! 600: sub do_msys_transform {
! 601: my ($path) = @_;
! 602: return undef if $^O ne 'msys';
! 603: return $path if $path eq '';
! 604:
! 605: # Remove leading double forward slashes, as they turn off Msys
! 606: # transforming.
! 607: $path =~ s{^/[/\\]+}{/};
! 608:
! 609: # Msys transforms automatically path to Windows native form in staring
! 610: # program parameters if program is not Msys-based.
! 611: # Note: already checked that $path is non-empty.
! 612: $path = `cmd //c echo '$path'`;
! 613: if($? != 0) {
! 614: warn "Can't transform path into Win32 form by using Msys" .
! 615: "internal transformation.\n";
! 616: return undef;
! 617: }
! 618:
! 619: # Remove double quotes, they are added for paths with spaces,
! 620: # remove both '\r' and '\n'.
! 621: $path =~ s{^\"|\"$|\"\r|\n|\r}{}g;
! 622:
! 623: return $path;
! 624: }
! 625:
! 626: # Internal function. Gets two parameters: first parameter must be single
! 627: # drive letter ('c'), second optional parameter is path relative to drive's
! 628: # current working directory. Returns Win32 absolute normalized path.
! 629: sub get_abs_path_on_win32_drive {
! 630: my ($drv, $rel_path) = @_;
! 631: my $res;
! 632:
! 633: # Get current directory on specified drive.
! 634: # "/c;" is compatible with both Msys and Cygwin.
! 635: my $cur_dir_on_drv = `cmd "/c;" echo %=$drv:%`;
! 636: if($? != 0) {
! 637: warn "Can't determine Win32 current directory on drive $drv:.\n";
! 638: return undef;
! 639: }
! 640:
! 641: if($cur_dir_on_drv =~ m{^[%]}) {
! 642: # Current directory on drive is not set, default is
! 643: # root directory.
! 644:
! 645: $res = ucfirst($drv) . ':/';
! 646: }
! 647: else {
! 648: # Current directory on drive was set.
! 649: # Remove both '\r' and '\n'.
! 650: $cur_dir_on_drv =~ s{\n|\r}{}g;
! 651:
! 652: # Append relative path part.
! 653: $res = $cur_dir_on_drv . '/';
! 654: }
! 655: $res .= $rel_path if defined $rel_path;
! 656:
! 657: # Replace any possible back slashes with forward slashes,
! 658: # remove any duplicated slashes, resolve relative dirs.
! 659: return normalize_path($res);
! 660: }
! 661:
! 662: # Internal function. Tries to find or guess Win32 version of given
! 663: # absolute Unix-style path. Other types of paths are not supported.
! 664: # Returned paths contain only single forward slashes (no back and
! 665: # duplicated slashes).
! 666: # Last resort. Used only when other transformations are not available.
! 667: sub do_dumb_guessed_transform {
! 668: my ($path) = @_;
! 669:
! 670: # Replace any possible back slashes and duplicated forward slashes
! 671: # with single forward slashes.
! 672: $path =~ s{[/\\]+}{/}g;
! 673:
! 674: # Empty path is not valid.
! 675: return undef if (length($path) == 0);
! 676:
! 677: # RE to find Win32 drive letter
! 678: my $drv_ltr_re = drives_mounted_on_cygdrive() ?
! 679: qr{^/cygdrive/([a-zA-Z])($|/.*$)} :
! 680: qr{^/([a-zA-Z])($|/.*$)};
! 681:
! 682: # Check path whether path is Win32 directly mapped drive and try to
! 683: # transform it assuming that drive letter is matched to Win32 drive letter.
! 684: if($path =~ m{$drv_ltr_re}) {
! 685: return ucfirst($1) . ':/' if(length($2) == 0);
! 686: return ucfirst($1) . ':' . $2;
! 687: }
! 688:
! 689: # This may be some custom mapped path. ('/mymount/path')
! 690:
! 691: # Must check longest possible path component as subdir can be mapped to
! 692: # different directory. For example '/usr/bin/' can be mapped to '/bin/' or
! 693: # '/bin/' can be mapped to '/usr/bin/'.
! 694: my $check_path = $path;
! 695: my $path_tail = '';
! 696: do {
! 697: if(-d $check_path) {
! 698: my $res =
! 699: `(cd "$check_path" && cmd /c "echo %__CD__%") 2>/dev/null`;
! 700: if($? == 0 && substr($path, 0, 1) ne '%') {
! 701: # Remove both '\r' and '\n'.
! 702: $res =~ s{\n|\r}{}g;
! 703:
! 704: # Replace all back slashes with forward slashes.
! 705: $res =~ s{\\}{/}g;
! 706:
! 707: if(length($path_tail) > 0) {
! 708: return $res . $path_tail;
! 709: }
! 710: else {
! 711: $res =~ s{/$}{} unless $check_path =~ m{/$};
! 712: return $res;
! 713: }
! 714: }
! 715: }
! 716: if($check_path =~ m{(^.*/)([^/]+/*)}) {
! 717: $check_path = $1;
! 718: $path_tail = $2 . $path_tail;
! 719: }
! 720: else {
! 721: # Shouldn't happens as root '/' directory should always
! 722: # be resolvable.
! 723: warn "Can't determine Win32 directory for path \"$path\".\n";
! 724: return undef;
! 725: }
! 726: } while(1);
! 727: }
! 728:
! 729:
! 730: # Internal function. Converts given Unix-style absolute path to Win32 format.
! 731: sub simple_transform_win32_to_unix {
! 732: my ($path) = @_;
! 733:
! 734: if(should_use_cygpath()) {
! 735: # 'cygpath' gives precise result.
! 736: my $res;
! 737: chomp($res = `cygpath -a -u '$path'`);
! 738: if($? != 0) {
! 739: warn "Can't determine Unix-style directory for Win32 " .
! 740: "directory \"$path\".\n";
! 741: return undef;
! 742: }
! 743:
! 744: # 'cygpath' removes last slash if path is root dir on Win32 drive.
! 745: $res .= '/' if(substr($res, length($res) - 1, 1) ne '/' &&
! 746: $path =~ m{[/\\]$});
! 747: return $res;
! 748: }
! 749:
! 750: # 'cygpath' is not available, use guessed transformation.
! 751: unless($path =~ s{^([a-zA-Z]):(?:/|\\)}{/\l$1/}) {
! 752: warn "Can't determine Unix-style directory for Win32 " .
! 753: "directory \"$path\".\n";
! 754: return undef;
! 755: }
! 756:
! 757: $path = '/cygdrive' . $path if(drives_mounted_on_cygdrive());
! 758: return $path;
! 759: }
! 760:
! 761: 1; # End of module
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>