At 1:06 AM +0100 11/16/03, Michael Lemke wrote:While doing some porting I noticed this inconsistency between Unix and VMS with catdir.
VMS> perl -e "use File::Spec::Functions; print catdir("""",'a','b'); [.a.b] VMS> perl -e "use File::Spec::Functions; print catdir("" "",'a','b'); a:[b]
I'd expect to get an absolute path in both cases. In fact, only the first
should give a correct answer. On Unix it behaves as I expect:
unix> perl -e "use File::Spec::Functions; print catdir('','a','b');"'print "\n";'
/a/b
unix> perl -e "use File::Spec::Functions; print catdir(' ','a','b');"'print "\n";'
/a/b
I'm not so sure that a zero-length string and a space should be
considered the same. But I agree the second VMS example is a bit odd
in that a space is not considered a volume name but the next element
in the list is. There may be a bug here, or it just may be undefined behavior.
I am not so sure either. The observed behavior on VMS led me to think catdir could do what I want. But taking this a bit further, how would I create a top level directory on Unix with catdir other than having the first argument empty? As you say, space and empty is not the same and creates different results on Unix: catdir('','a','b') -> '/a/b' catdir(' ','a','b) -> ' /a/b' catdir('a','b') -> 'a/b'
So in analogy I'd consider
catdir('','a','b') -> 'a:[b]'
a quite sensible result. It is the closest VMS translation for /a/b.
Although one could also find arguments for returning [a.b].
This is with perl 5.8.2 and the File::Spec that comes with it.
This problem prevents me to do this:
catdir( split('/','/some/absolute/path') );
Or more to the point, how do you do this in a portable way:
$r = '/root'; $y = $r . '/subdir/subsubdir'; $z = $r . '/subdir1';
The first thing to remember if you want to be portable is never to look for a particular, platform-specific directory separator. The implication here would be to refrain from using split().
My idea here was to use the Unix syntax as the starting point and have catdir and friends make the OS specific version from it. That is to avoid stuff like
$r = '/root' if $^O eq 'unix'; $r = 'root:' if $^O eq 'vms'; $r = 'C:' if $^O eq 'win'; $r = 'whatever' if $^O eq 'mac';
Have a look at File::Spec->splitpath(). As Michael suggested, also look at catpath() for putting the pieces back together.
In fact I had and that is where I got the problem.
A400> typ x.pl
use File::Spec::Functions qw/splitpath catpath catdir/;
($v,$d,$f) = splitpath('root:[a]');
$x = catpath( $v, catdir( $d, 'b'), $f );
print "$x\n";A400> perl x.pl root:[a.b]
But:
A400> typ x.pl
use File::Spec::Functions qw/splitpath catpath catdir/;
($v,$d,$f) = splitpath('root:');
$x = catpath( $v, catdir( $d, 'b'), $f );
print "$x\n";A400> perl x.pl root:[.b]
And this is only because catdir tosses off the empty $d. Think this through for Unix with /root and /root/a and you'd get what is intended. $v would just be empty.
Michael
