Annotation of embedaddon/curl/tests/pathhelp.pm, revision 1.1.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>