Boost logo

Boost :

From: Angus Leeming (angus.leeming_at_[hidden])
Date: 2004-09-29 06:10:21


Martin wrote:

> How do I use it in windows where case-sensitivity is a file
> attribute (FILE_FLAG_POSIX_SEMANTICS).
>
> boost::glob("*.[tT][xX][tT]", ...)
>
> might return more files than
>
> FindFirstFile("*.txt")/FindNextFile()
>
> e.g. on a mounted case-sensitive filesystem

Good morning, Martin.

Having slept on it, I think that my original answer of "ask Beman" is
wrong. I think that handling this requirement is easy.

In boost/details/glob.hpp you'll find

template <typename TraitsT = glob_traits>
class glob_predicate
{
    ...
public:
    /** @returns true if @c p.leaf() matches the glob expression. */
    bool operator()(filesystem::path const & p) const
    {
        if (contains_wildcards_) {
            boost::cmatch match_;
            return regex_match(p.leaf().c_str(), match_, regex_);
        }

        return p.leaf() == pattern_;
    }
};

I have two suggestions:
1. Add the ability to ignore case for all users:

#include <boost/algorithm/case_conv.hpp>

enum glob_flags {
    ...
    glob_case_insensitive = (1 << 5)
};

template <typename TraitsT = glob_traits>
class glob_predicate
{
    bool case_insensitive_;
public:
    glob_predicate(std::string const & pattern, glob_flags flags)
        : regex_(reg_expression())
        , case_insensitive(flags & glob_case_insensitive)
    { ... }

    bool operator()(filesystem::path const & p) const
    {
        std::string const leaf = case_insensitive_ ?
            to_lower_copy(p.leaf()) : p.leaf();

        if (contains_wildcards_) {
            boost::cmatch match_;
            return regex_match(leaf.c_str(), match_, regex_);
        }

        return leaf == pattern_;
    }
};

2. Interrogate the value of FILE_FLAG_POSIX_SEMANTICS on Windows
boxes. I'm no Windows programmer, but a quick google suggests that
this might do the trick. Feel free to improve:

bool operator()(filesystem::path const & p) const
{
    bool case_insensitive = case_insensitive_;

#ifdef BOOST_WINDOWS
    if (!case_insensitive) {
        WIN32_FILE_ATTRIBUTE_DATA data;
        if (GetFileAttributesEx(p.native_file_string(), 0, data)) {
            case_insensitive =
                !(data.fileAttributes & FILE_FLAG_POSIX_SEMANTICS);
        }
    }
#endif

    ...
}

I have one further question for you, however. If the 'top level'
pattern doesn not contain any wild cards (foo.cpp in ../*/foo.cpp),
then I use
        fs::path const candidate = working_dir /= predicate.file();
        if (exists(candidate)
                matches.push_back(candidate);

So, will 'exists' do the right thing here?

Any other comments?

Regards,
Angus


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk