line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Path::ExpandTilde; |
2
|
|
|
|
|
|
|
|
3
|
1
|
|
|
1
|
|
8797
|
use strict; |
|
1
|
|
|
|
|
21
|
|
|
1
|
|
|
|
|
30
|
|
4
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
5
|
1
|
|
|
1
|
|
5
|
use Carp 'croak'; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
80
|
|
6
|
1
|
|
|
1
|
|
12
|
use Exporter; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
48
|
|
7
|
1
|
|
|
1
|
|
5
|
use File::Glob ':glob'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
226
|
|
8
|
1
|
|
|
1
|
|
6
|
use File::Spec; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
175
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our $VERSION = '0.001'; |
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our @ISA = 'Exporter'; |
13
|
|
|
|
|
|
|
our @EXPORT = 'expand_tilde'; |
14
|
|
|
|
|
|
|
|
15
|
1
|
50
|
|
|
|
129
|
use constant BSD_GLOB_FLAGS => GLOB_NOCHECK | GLOB_QUOTE | GLOB_TILDE | GLOB_ERR |
16
|
|
|
|
|
|
|
# add GLOB_NOCASE as in File::Glob |
17
|
1
|
|
|
1
|
|
7
|
| ($^O =~ m/\A(?:MSWin32|VMS|os2|dos|riscos)\z/ ? GLOB_NOCASE : 0); |
|
1
|
|
|
|
|
1
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# File::Glob did not try %USERPROFILE% (set in Windows NT derivatives) for ~ before 5.16 |
20
|
1
|
|
33
|
1
|
|
6
|
use constant WINDOWS_USERPROFILE => $^O eq 'MSWin32' && $] < 5.016; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
72
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# File::Glob does not have bsd_glob on 5.6.0, but its glob was the same then |
23
|
1
|
50
|
|
1
|
|
293
|
BEGIN { *bsd_glob = \&File::Glob::glob if $] == 5.006 } |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
sub expand_tilde { |
26
|
18
|
|
|
18
|
1
|
6337
|
my ($dir) = @_; |
27
|
18
|
50
|
|
|
|
39
|
return undef unless defined $dir; |
28
|
18
|
100
|
|
|
|
81
|
return File::Spec->canonpath($dir) unless $dir =~ m/^~/; |
29
|
|
|
|
|
|
|
# parse path into segments |
30
|
13
|
|
|
|
|
70
|
my ($volume, $directories, $file) = File::Spec->splitpath($dir, 1); |
31
|
13
|
|
|
|
|
52
|
my @parts = File::Spec->splitdir($directories); |
32
|
13
|
|
|
|
|
23
|
my $first = shift @parts; |
33
|
13
|
50
|
|
|
|
24
|
return File::Spec->canonpath($dir) unless defined $first; |
34
|
|
|
|
|
|
|
# expand first segment |
35
|
13
|
|
|
|
|
13
|
my $expanded; |
36
|
13
|
|
|
|
|
24
|
if (WINDOWS_USERPROFILE and $first eq '~') { |
37
|
|
|
|
|
|
|
$expanded = $ENV{HOME} || $ENV{USERPROFILE}; |
38
|
|
|
|
|
|
|
} else { |
39
|
13
|
|
|
|
|
28
|
(my $pattern = $first) =~ s/([\\*?{[])/\\$1/g; |
40
|
13
|
|
|
|
|
299
|
($expanded) = bsd_glob($pattern, BSD_GLOB_FLAGS); |
41
|
13
|
50
|
|
|
|
51
|
croak "Failed to expand $first: $!" if GLOB_ERROR; |
42
|
|
|
|
|
|
|
} |
43
|
13
|
100
|
66
|
|
|
71
|
return File::Spec->canonpath($dir) if !defined $expanded or $expanded eq $first; |
44
|
|
|
|
|
|
|
# replace first segment with new path |
45
|
12
|
|
|
|
|
96
|
($volume, $directories) = File::Spec->splitpath($expanded, 1); |
46
|
12
|
|
|
|
|
65
|
$directories = File::Spec->catdir($directories, @parts); |
47
|
12
|
|
|
|
|
161
|
return File::Spec->catpath($volume, $directories, $file); |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
1; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
=head1 NAME |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
Path::ExpandTilde - Expand tilde (~) to homedir in file paths |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
=head1 SYNOPSIS |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
use Path::ExpandTilde; |
59
|
|
|
|
|
|
|
my $homedir = expand_tilde('~'); |
60
|
|
|
|
|
|
|
my $bashrc = expand_tilde('~/.bashrc'); |
61
|
|
|
|
|
|
|
my $pg_home = expand_tilde('~postgres'); |
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
=head1 DESCRIPTION |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
This module uses C from L to portably expand a leading |
66
|
|
|
|
|
|
|
tilde (C<~>) in a file path into the current or specified user's home |
67
|
|
|
|
|
|
|
directory. No other L are |
68
|
|
|
|
|
|
|
expanded. |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
=head1 FUNCTIONS |
71
|
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
=head2 expand_tilde |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
my $new_path = expand_tilde($path); |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
Exported by default. If the path starts with C<~>, expands that to the current |
77
|
|
|
|
|
|
|
user's home directory. If the path starts with C<< ~I >>, expands |
78
|
|
|
|
|
|
|
that to the specified user's home directory. If the user doesn't exist, no |
79
|
|
|
|
|
|
|
expansion is done. The returned path is canonicalized as by |
80
|
|
|
|
|
|
|
L either way. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=head1 NOTES |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
The algorithm should be portable to most operating systems supported by Perl, |
85
|
|
|
|
|
|
|
though the home directory may not be found by C on some. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head1 BUGS |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
Report any issues on the public bugtracker. |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
=head1 AUTHOR |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Dan Book |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=head1 COPYRIGHT AND LICENSE |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
This software is Copyright (c) 2018 by Dan Book. |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
This is free software, licensed under: |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
=head1 SEE ALSO |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
L, L, L |