std.path review: update

Lars T. Kyllingstad public at kyllingen.NOSPAMnet
Wed Jul 20 10:36:51 PDT 2011


On Mon, 18 Jul 2011 14:51:06 -0400, Steven Schveighoffer wrote:

> On Mon, 18 Jul 2011 14:25:57 -0400, Lars T. Kyllingstad
> <public at kyllingen.nospamnet> wrote:
> 
>> On Mon, 18 Jul 2011 13:16:29 -0400, Steven Schveighoffer wrote:
> 
>>> In driveName:
>>>
>>> Should std.path handle uunc paths?  i.e. \\servername\share\path  (I
>>> think if it does, it should specify \\servername\share as the drive)
>>
>> Yes, std.path is supposed to support UNC paths.  For instance, the
>> following works now:
>>
>>   assert (equal(pathSplitter(`\\foo\bar\baz`), [`\\foo`, "bar",
>>   "baz"]));
>>
>> I guess you would rather have that
>>
>>   assert (equal(pathSplitter(`\\foo\bar\baz`), [`\\foo\bar`, "baz"]));
>>
>> then?  I am not very familiar with Windows network shares; is \\foo
>> never a valid path on its own?
> 
> It is and it isn't.

Well, that certainly cleared things up. ;)


> It's *not* a normal directory, because only shares
> can be in that directory.  In other words, the point at which a UNC path
> turns into normal directory structure is after the share name.
> 
> An easy way to compare is, you can only map drive letters to shares, not
> to servers.

Then driveName() should probably return the full share path.  But, of the 
following asserts, which should pass?

    assert (pathSplitter(`\\foo\bar\baz`).front == `\\foo\bar`);
    assert (pathSplitter(`\\foo\bar\baz`).front == `\\foo`);

    assert (baseName(`\\foo\bar`) == `\\foo\bar`);
    assert (baseName(`\\foo\bar`) == "bar");

    assert (dirName(`\\foo\bar`) == `\\foo\bar`);
    assert (dirName(`\\foo\bar`) == `\\foo`);

Note that if you replace `\\foo\bar` with `c:\` in the above, the first 
assert in each pair will pass.  Same with "/" on POSIX.  Basically, that 
choice corresponds to treating `\\foo\bar` as a filesystem root.


>> As I understand it, some POSIX systems also mount network drives using
>> similar paths.  Does anyone know whether "//foo" is a valid path on
>> these systems, or does it have to bee "//foo/bar"?
> 
> Typically, linux uses URL's, i.e. smb://server/share   URL parsing is
> probably not in std.path's charter.
> 
> However, I have used a command like:
> 
> mount -t cifs //server/share /mnt/serverfiles
> 
> But this is only in very special contexts.  In general I don't think
> //foo should be considered a server path on Posix systems.

I actually got a request on the Phobos list that std.path should support 
such paths.  Furthermore, the POSIX stardard explicitly mentions "//" 
paths (though it basically says it is implementation-defined whether to 
bother dealing with them).


>>> joinPath:
>>>
>>> Does this normalize the paths?  For example:
>>>
>>> joinPath("/home/steves", "../lars") => /home/steves/../lars or
>>> /home/lars ?
>>>
>>> If so, the docs should reflect that.  If not, maybe it should :)  If
>>> it doesn't, at least the docs should state that it doesn't.
>>
>> No, it doesn't, and I don't think it should.  It is better to let the
>> user choose whether they want the overhead of normalization by calling
>> normalize() explicitly.  I will specify this in the docs.
> 
> In fact, if you do not normalize during the join, it's *more* overhead
> to normalize afterwards.  If normalization is done while joining, then
> you only build one string.  There's no need to build a non-normalized
> string, then build a normalized string based on that.
> 
> Plus the data is only iterated once.
> 
> I think it's at least worth an option, but I'm not going to hold back my
> vote based on this :)

If it doesn't turn out to be a huge undertaking, I think I'll replace 
joinPath() with a function buildPath() that takes an input range of path 
segments and joins them together, with optional normalization.  Then, 
normalize(path) can be implemented as:

    buildPath(pathSplitter(path));

Does that sound sensible?


>>> pathSplitter:
>>>
>>> I think this should be a bi-directional range (no technical limitation
>>> I can think of).
>>
>> It is more of a complexity vs. benefit thing, but as you are the second
>> person to ask for this, I will look into it.  A convincing use case
>> would be nice, though. :)
> 
> Well a path is more like a stack than a queue.  You are usually
> operating more on the back side of it.  To provide back and popBack
> makes a lot of sense to me.  For example, to implement the command cd
> ../foo, you need to popBack the topmost directory.

Ok, I'll see what I can do about it. :)


>>> fcmp:
>>> "On Windows, fcmp is an alias for std.string.icmp, which yields a case
>>> insensitive comparison. On POSIX, it is an alias for
>>> std.algorithm.cmp, i.e. a case sensitive comparison."
>>>
>>> What about comparing c:/foo with c:\foo?  This isn't going to be equal
>>> with icmp.
>>
>> I am a bit unsure what to do about the comparison functions (fcmp,
>> pathCharMatch and globMatch).  Aside from the issue with directory
>> separators it is, as was pointed out by someone else, entirely possible
>> to mount case-sensitive file systems on Windows and case-insensitive
>> file systems on POSIX.  (The latter is not uncommon on OSX, I believe.)
>>  I am open to suggestions.
> 
> It's definitely something to think about.  At the very least, I think
> the default file system case sensitivity should be mapped to a certain
> function.  It doesn't hurt to expose the opposite sensitivity as an
> alternate (you need to implement both anyway).  A template with all
> options defaulted for the current OS makes good sense I think. 
> Actually, expanding/renaming pathCharMatch provides a perfect way to
> default these:
> 
> e.g.:
> version(Windows)
> {
>     enum defaultOSSensitivity = false;
>     enum defaultOSDirSeps = `\/`;
> }
> else version(Posix)
> {
>     enum defaultOSSensitivity = true;
>     enum defaultOSDirSeps = "/";
> }
> 
> // replaces pathCharMatch
> int pathCharCmp(bool caseSensitive = defaultOSSensitivity, string
> dirseps = defaultOSDirSeps)(dchar a, dchar b);
> 
> int fcmp(alias pred = "pathCharCmp(a, b)", S1, S2)(S1 filename1, S2
> filename2);
> 
> Anyone who wants to do alternate comparisons is free to do so using
> other options from pathCharCmp.

Good idea.  I'll probably implement something like that.


>>> expandTilde:
>>>
>>> I've commented on expandTilde from the other posts, but if it is kept
>>> a posix-only function, the documentation should reflect that.
>>
>> It does; look at the "Returns" section.  Perhaps it should be moved to
>> a more prominent location?
> 
> Yes.  It should say (Posix-only).  I believe technically that it should
> fail to compile on Windows if it does not map to a "home" directory
> there.  Note that as named, it's possible to confuse with expanding the
> DOS 8.3 name of a file, i.e. Progra~1

I agree.  I'll put it inside a version(Posix) block.

-Lars


More information about the Digitalmars-d mailing list