Sponsored Link •
|
This page shows globsequencemethods.h
, which is described
in the article, "Wild-card Searches of UNIX Directories with Random-Access Iterators":
// globsequencemethods.h: Definition of the unixstl::glob_sequence class ... // Includes (as shown in globsequence.h) inline /* explicit */ glob_sequence::glob_sequence(char_type const *pattern, unsigned flags /* = noSort */) : m_flags(validate_flags_(flags)) , m_buffer(1) { m_cItems = init_glob_(NULL, pattern); unixstl_assert((0 == m_cItems) == (NULL == m_base)); } inline glob_sequence::glob_sequence(char_type const *directory, char_type const *pattern, unsigned flags /* = noSort */) : m_flags(validate_flags_(flags)) , m_buffer(1) { m_cItems = init_glob_(directory, pattern); unixstl_assert((0 == m_cItems) == (NULL == m_base)); } inline glob_sequence::~glob_sequence() { unixstl_assert((0 == m_cItems) == (NULL == m_base)); if(NULL != m_base) { globfree(&m_glob); } } inline size_t glob_sequence::size() const { return m_cItems; } inline us_bool_t glob_sequence::empty() const { return 0 == size(); } inline value_type const glob_sequence::operator [](size_type index) const { unixstl_message_assert("index access out of range in glob_sequence", index < 1 + size()); // Has to be +1, since legitimate to take address of one-past-the-end return m_base[index]; } inline const_iterator glob_sequence::begin() const { return m_base; } inline const_iterator glob_sequence::end() const { return m_base + m_cItems; } #ifdef __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT inline const_reverse_iterator glob_sequence::rbegin() const { return const_reverse_iterator(end()); } inline const_reverse_iterator glob_sequence::rend() const { return const_reverse_iterator(begin()); } #endif /* __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT */ inline /* static */ unsigned glob_sequence::validate_flags_(unsigned flags) { if(0 == (flags & (directories | files))) { flags |= (directories | files); } if(0 == (flags & directories)) { // It's more efficient to not bother doing a separate dots check if all // directories are being elided. flags |= includeDots; // Since we're not going to be returning directories to the caller, and // it's more efficient to believe the glob() directory marking rather // than calling stat, we add the markDirs flag here. flags |= markDirs; } return flags; } inline /* static */ us_bool_t glob_sequence::is_end_of_path_elements_(char_type const *pch, difference_type index) { return pch[index] == '\0' || ( pch[index + 1] == '\0' && pch[index] == '/'); } inline /* static */ us_bool_t glob_sequence::is_dots_maybe_slashed_(char_type const *s, us_bool_t &bTwoDots) { unixstl_assert(NULL != s); return s[0] == '.' && ( (bTwoDots = false, is_end_of_path_elements_(s, 1)) || (bTwoDots = true, ( s[1] == '.' && is_end_of_path_elements_(s, 2)))); } inline size_t glob_sequence::init_glob_(char_type const *directory, char_type const *pattern) { unixstl_message_assert("Null pattern given to glob_sequence", NULL != pattern); unsigned glob_flags = 0; basic_file_path_bufferscratch_; // Scratch buffer for directory / pattern #ifndef __STLSOFT_CF_EXCEPTION_SUPPORT if(0 == scratch_.size()) { m_base = NULL; return 0; } #endif /* !__STLSOFT_CF_EXCEPTION_SUPPORT */ // If a directory is given, then ... if( NULL != directory && '\0' != *directory) { // ... optionally turn it into an absolute directory, ... if(absolutePath == (m_flags & absolutePath)) { traits_type::get_full_path_name(directory, scratch_.size(), &scratch_[0]); } else { traits_type::str_copy(&scratch_[0], directory); } // ... ensure that it has a trailing path name-separator, and ... traits_type::ensure_dir_end(&scratch_[0]); // ... prefix directory onto pattern. traits_type::str_cat(&scratch_[0], pattern); pattern = c_str_ptr(scratch_); } if(m_flags & noSort) { // Don't bother sorting glob_flags |= GLOB_NOSORT; } if(m_flags & markDirs) { // Ask for trailing slashes on directories glob_flags |= GLOB_MARK; } if(directories == (m_flags & (directories | files))) { // Ask for only directories glob_flags |= GLOB_ONLYDIR; } int gr = glob(pattern, glob_flags, NULL, &m_glob); if(0 != gr) { #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT throw glob_sequence_exception(gr, 0); #endif /* __STLSOFT_CF_EXCEPTION_SUPPORT */ m_base = NULL; return 0; } else { char_type **base = m_glob.gl_pathv; size_t cItems = static_cast (m_glob.gl_pathc); // If we are eliding dots, or trimming out directories, then // we'll copy the pointers into the buffer, and process them // there if( 0 == (m_flags & includeDots) || (m_flags & (directories | files)) == files) { #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT try { m_buffer.resize(cItems); } catch(...) { globfree(&m_glob); throw; } #else /* __STLSOFT_CF_EXCEPTION_SUPPORT */ if(!m_buffer.resize(cItems)) { globfree(&m_glob); m_base = NULL; return 0; } #endif /* __STLSOFT_CF_EXCEPTION_SUPPORT */ unixstl_assert(m_buffer.size() == cItems); base = static_cast (memcpy(&m_buffer[0], base, m_buffer.size() * sizeof(char_type*))); } if(0 == (m_flags & includeDots)) { // Now remove the dots. If located at the start of // the gl buffer, then simply increment m_base to // be above that. If not then rearrange the base // two pointers such that they are there. us_bool_t foundDot1 = false; us_bool_t foundDot2 = false; char_type **begin = base; char_type **end = begin + cItems; for(; begin != end; ++begin) { us_bool_t bTwoDots; if(is_dots_maybe_slashed_(*begin, bTwoDots)) { // Swap with whatever is at base[0] if(begin != base) { std::swap(*begin, *base); } ++base; --cItems; // We're only going to get one "." and one ".." (bTwoDots ? foundDot2 : foundDot1) = true; if( foundDot1 && foundDot2) { break; } } } } // We should be able to trust glob() to return only directories when // asked, so we assume the following only needs to be done when // have asked for files alone if((m_flags & (directories | files)) == files) { basic_file_path_buffer buffer; char_type **begin = base; char_type **end = begin + cItems; #ifndef __STLSOFT_CF_EXCEPTION_SUPPORT if(0 == buffer.size()) { globfree(&m_glob); m_base = NULL; return 0; } #endif /* !__STLSOFT_CF_EXCEPTION_SUPPORT */ for(; begin != end; ++begin) { // Now need to process the file, by using stat struct stat st; int res; char_type const *entry = *begin; // TODO: If not ultra-cautious, and asked for markDirs, then trust unixstl_assert(files == (m_flags & (directories | files))); if( 0 == (m_flags & markDirs) || !traits_type::has_dir_end(entry)) { if(markDirs == (m_flags & markDirs)) { traits_type::str_copy(&buffer[0], entry); traits_type::remove_dir_end(&buffer[0]); entry = buffer.c_str(); } res = stat(entry, &st); if(0 != res) { // We could throw an exception here, but it might just be // the case that a file has been deleted subsequent to its // having been included in the glob list. As such, it makes // more sense to just kick it from the list } else { if(m_flags & files) // Want files { if(S_IFREG == (st.st_mode & S_IFREG)) { continue; // A file, so accept it } } } } // Note that there is no test here to determine whether or not // begin == base. It is assumed that most cases of file elision // will involve several files - how many directories have just // one file in them? - so the test would actually be a // pessimisation // Swap with whatever is at base[0] std::swap(*begin, *base); ++base; --cItems; } } // Ensure we've not corrupted the sort order if( 0 == (m_flags & noSort) && cItems != static_cast (m_glob.gl_pathc)) { unixstl_ns_qual_std(sort)(base, base + cItems); } // Set m_base and m_cItems to the correct values, with // or without dots. m_base is cast here to remove the // need for const-casting throughout the rest of the // class m_base = const_cast (base); return cItems; } }
Sponsored Links
|