[filesystem.v3] possible bug in replace_extension

replace_extension seems to have the wrong behaviour if the provided new extension does not start with a dot. The following program: #include <iostream> #include <boost/filesystem.hpp> int main() { boost::filesystem::path p("foo.bar"); std::cout<<p<<'\n'; p.replace_extension("foo"); std::cout<<p<<'\n'; return 0; } built with the following command line on linux 64 (with boost 1.48.0): $ g++-4.6.2 -DBOOST_DISABLE_ASSERTS -DBOOST_FILESYSTEM_VERSION=3 -DBOOST_FILESYSTEM_NO_DEPRECATED -o toto -I/soft/bal/usr/gcc-release/boost/include toto.cc -L/soft/bal/usr/gcc-release/boost/lib -lboost_filesystem -lboost_system produces the following output: "foo.bar" "foo" but should produce: "foo.bar" "foo.foo" as read from the documentation path& replace_extension(const path& new_extension = path()); Postcondition: extension() == replacement, where replacement is new_extension if new_extension.empty() || new_extension[0] == the dot character, otherwise replacement is the dot character followed by new_extension. Adding the dot before foo makes the program work: p.replace_extension(".foo"); This seemed to work with filesystem v2. Frédéric Bron

replace_extension seems to have the wrong behaviour if the provided new extension does not start with a dot.
I found that this has already been registered a long time ago: https://svn.boost.org/trac/boost/ticket/5118 (at the time of 1.45.0). A patch has even been proposed. Could it be fixed for 1.49.0? Kind regards, Frédéric

Frédéric Bron wrote:
replace_extension seems to have the wrong behaviour if the provided new extension does not start with a dot.
I found that this has already been registered a long time ago: https://svn.boost.org/trac/boost/ticket/5118 (at the time of 1.45.0). A patch has even been proposed. Could it be fixed for 1.49.0?
I ran into this today. The issue is that replace_extension() extracts the extension() from its argument and uses that as the new extension. Thus, if there's no dot in the argument, it has no extension. That's reasonable for a path argument. Indeed, I think the patch is wrong. The confusion comes when the argument is a string. An implicit path is constructed from the string and, since it has no dot, there's no extension to replace. I think there should be an overload that takes a string. Then, the whole argument is used as the extension, if it contains no dot, and the tail is used if there is. Reasonable? _____ Rob Stewart robert.stewart@sig.com Software Engineer using std::disclaimer; Dev Tools & Components Susquehanna International Group, LLP http://www.sig.com ________________________________ IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.

I ran into this today. The issue is that replace_extension() extracts the extension() from its argument and uses that as the new extension. Thus, if there's no dot in the argument, it has no extension. That's reasonable for a path argument. Indeed, I think the patch is wrong. The confusion comes when the argument is a string. An implicit path is constructed from the string and, since it has no dot, there's no extension to replace. I think there should be an overload that takes a string. Then, the whole argument is used as the extension, if it contains no dot, and the tail is used if there is. Reasonable?
And this explains why it worked perfectly with v2 which used a string as argument. Thanks for looking at this. Frédéric

2012/2/11 Frédéric Bron <frederic.bron@m4x.org>
[...] And this explains why it worked perfectly with v2 which used a string as argument.
Yes, filesystem v3 misuses paths as strings. Beman: this is one of the items in my list of what's bad in boost::filesystem. And apparently I'm not the only one who thinks so: On Wed, Feb 1, 2012 at 13:08, Thorsten Ottosen <thorsten.ottosen@dezide.com>wrote:
Remark 2: The fact that functions like extension() returns a temporary path object seems overkill (I know its only a cheap string copy, but still). I fail to see how ".foo" can be a path.
Me too. Nor why *p.begin() is a path. It's correct that (almost) every string can be treated as a path, but it doesn't mean that it has to. Also you said (N3363): Users are misusing paths as general string containers because they provide
interoperability.
Ironically boost::filesystem does the same thing. (And in fact it's the only code I've seen misusing boost::filesystem::path as described.) -- Yakov

On Sat, Feb 11, 2012 at 00:42, Yakov Galka <ybungalobill@gmail.com> wrote:
Also you said (N3363):
Typo, N3336: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3336.html -- Yakov
participants (3)
-
Frédéric Bron
-
Stewart, Robert
-
Yakov Galka