00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059 #ifndef UNIXSTL_INCL_H_UNIXSTL
00060 # include "unixstl.h"
00061 #endif
00062 #ifndef UNIXSTL_INCL_H_UNIXSTL_FILESYSTEM_TRAITS
00063 # include "unixstl_filesystem_traits.h"
00064 #endif
00065 #ifndef UNIXSTL_INCL_H_UNIXSTL_FILE_PATH_BUFFER
00066 # include "unixstl_file_path_buffer.h"
00067 #endif
00068 #ifndef STLSOFT_INCL_H_STLSOFT_ITERATOR
00069 # include "stlsoft_iterator.h"
00070 #endif
00071 #ifndef STLSOFT_INCL_H_STLSOFT_AUTO_BUFFER
00072 # include "stlsoft_auto_buffer.h"
00073 #endif
00074 #ifndef STLSOFT_INCL_H_STLSOFT_MALLOC_ALLOCATOR
00075 # include "stlsoft_malloc_allocator.h"
00076 #endif
00077 #include <sys/types.h>
00078 #include <sys/stat.h>
00079 #include <errno.h>
00080 #include <glob.h>
00081 #include <algorithm>
00082 #include <utility>
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 #ifdef _STLSOFT_NO_NAMESPACES
00103 # define _UNIXSTL_NO_NAMESPACES
00104 #endif
00105
00106
00107 #ifdef _UNIXSTL_NO_NAMESPACES
00108 # define _UNIXSTL_NO_NAMESPACE
00109 #endif
00110
00111 #ifndef _UNIXSTL_NO_NAMESPACE
00112 # if defined(_STLSOFT_NO_NAMESPACE) || \
00113 defined(__STLSOFT_DOCUMENTATION_SKIP_SECTION)
00114
00115 namespace unixstl
00116 {
00117 # else
00118
00119
00120 namespace stlsoft
00121 {
00122
00123 namespace unixstl_project
00124 {
00125
00126 # endif
00127 #endif
00128
00129
00130
00133
00137
00142
00143
00144
00145
00146
00147 #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT
00151 class glob_sequence_exception
00152 #if defined(__STLSOFT_COMPILER_IS_DMC)
00153 : public std::exception
00154 #else
00155 : public unixstl_ns_qual_std(exception)
00156 #endif
00157 {
00160 public:
00161 #if defined(__STLSOFT_COMPILER_IS_DMC)
00162 typedef std::exception parent_class_type;
00163 #else
00164 typedef unixstl_ns_qual_std(exception) parent_class_type;
00165 #endif
00166 typedef glob_sequence_exception class_type;
00168
00171 public:
00172 ss_explicit_k glob_sequence_exception(us_int_t globStatus, us_int_t errno_) unixstl_throw_0()
00173 : m_globStatus(globStatus)
00174 , m_errno(errno_)
00175 {}
00177
00180 public:
00181 #if defined(__STLSOFT_COMPILER_IS_DMC)
00182 char const *what() const throw()
00183 #else
00184 char const *what() const unixstl_throw_0()
00185 #endif
00186 {
00187 return "glob_sequence failure";
00188 }
00189
00190 us_int_t get_globstatus() const unixstl_throw_0()
00191 {
00192 return m_globStatus;
00193 }
00194 us_int_t get_errno() const unixstl_throw_0()
00195 {
00196 return m_errno;
00197 }
00199
00200
00201 private:
00202 us_int_t const m_globStatus;
00203 us_int_t const m_errno;
00204
00205
00206 private:
00207 class_type &operator =(class_type const &);
00208 };
00209
00210 #endif
00211
00216
00217 class glob_sequence
00218 {
00221 public:
00222
00223 typedef glob_sequence class_type;
00225 typedef us_char_a_t char_type;
00226
00227 typedef filesystem_traits<char_type> traits_type;
00229 typedef char_type const *value_type;
00231 typedef value_type const &const_reference;
00233 typedef value_type const *const_pointer;
00235 typedef us_size_t size_type;
00237 typedef us_ptrdiff_t difference_type;
00238
00240 typedef stlsoft_ns_qual(pointer_iterator)< value_type const
00241 , const_pointer
00242 , const_reference
00243 >::iterator_type const_iterator;
00244
00245 #ifdef __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT
00246
00247 typedef stlsoft_ns_qual(reverse_iterator_base) < const_iterator
00248 , value_type
00249 , const_reference
00250 , const_pointer
00251 , difference_type
00252 > const_reverse_iterator;
00253 #endif
00254
00255
00258 public:
00259 enum
00260 {
00261 includeDots = 0x0008
00262 , directories = 0x0010
00263 , files = 0x0020
00264 , noSort = 0x0100
00265 , markDirs = 0x0200
00266 , absolutePath = 0x0400
00267 ,
00268 };
00270
00273 public:
00284 ss_explicit_k glob_sequence(char_type const *pattern, us_uint_t flags = noSort);
00285
00297 glob_sequence(char_type const *directory, char_type const *pattern, us_uint_t flags = noSort);
00298
00299
00300 ~glob_sequence() unixstl_throw_0();
00302
00305 public:
00307 us_size_t size() const;
00308
00310 us_bool_t empty() const;
00311
00315 const value_type operator [](size_type index) const;
00317
00320 public:
00324 const_iterator begin() const;
00328 const_iterator end() const;
00329
00330 #ifdef __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT
00334 const_reverse_iterator rbegin() const;
00338 const_reverse_iterator rend() const;
00339 #endif
00340
00341
00342
00343 private:
00344 static us_uint_t validate_flags_(us_uint_t flags);
00345
00346
00347 static us_bool_t is_end_of_path_elements_(char_type const *pch, difference_type index);
00348
00349 static us_bool_t is_dots_maybe_slashed_(char_type const *s, us_bool_t &bTwoDots);
00350
00351 us_size_t init_glob_(char_type const *directory, char_type const *pattern);
00352
00353
00354 private:
00355 typedef stlsoft_ns_qual(auto_buffer)<char_type*, stlsoft_ns_qual(malloc_allocator)<char_type*>, 32> buffer_type;
00356
00357 us_uint_t const m_flags;
00358 char_type const **m_base;
00359 us_size_t m_cItems;
00360 buffer_type m_buffer;
00361 glob_t m_glob;
00362
00363
00364 private:
00365 glob_sequence(class_type const &);
00366 class_type const &operator =(class_type const &);
00367 };
00368
00370
00371
00372 #ifdef STLSOFT_UNITTEST
00373
00374 namespace unittest
00375 {
00376 ss_bool_t test_unixstl_glob_sequence(unittest_reporter *r)
00377 {
00378 using stlsoft::unittest::unittest_initialiser;
00379
00380 ss_bool_t bSuccess = true;
00381
00382 unittest_initialiser init(r, "UNIXSTL", "glob_sequence", __FILE__);
00383
00384 #if defined(WIN32) || \
00385 defined(_WIN32)
00386 glob_sequence seq("*.*");
00387 #else
00388 glob_sequence seq("*");
00389 #endif
00390
00391 if(seq.empty() != (0 == seq.size()))
00392 {
00393 r->report("glob_sequence empty() and size() contradict ", __LINE__);
00394 bSuccess = false;
00395 }
00396
00397 us_size_t total_forward = 0;
00398 us_size_t total_backward = 0;
00399
00400 glob_sequence::const_iterator b_f = seq.begin();
00401 for(; b_f != seq.end(); ++b_f)
00402 {
00403 total_forward += strlen(*b_f);
00404 }
00405
00406 glob_sequence::const_reverse_iterator b_b = seq.rbegin();
00407 for(; b_b != seq.rend(); ++b_b)
00408 {
00409 total_backward += strlen(*b_b);
00410 }
00411
00412 if(total_forward != total_backward)
00413 {
00414 r->report("glob_sequence forward and backward ranges contradict ", __LINE__);
00415 bSuccess = false;
00416 }
00417
00418 return bSuccess;
00419 }
00420
00421 unittest_registrar unittest_unixstl_glob_sequence(test_unixstl_glob_sequence);
00422
00423 }
00424
00425 #endif
00426
00427
00428
00429
00430
00431 inline glob_sequence::glob_sequence(glob_sequence::char_type const *pattern, us_uint_t flags )
00432 : m_flags(validate_flags_(flags))
00433 , m_buffer(1)
00434 {
00435 m_cItems = init_glob_(NULL, pattern);
00436
00437 unixstl_assert((0 == m_cItems) || (NULL != m_base));
00438 }
00439
00440 inline glob_sequence::glob_sequence(glob_sequence::char_type const *directory, glob_sequence::char_type const *pattern, us_uint_t flags )
00441 : m_flags(validate_flags_(flags))
00442 , m_buffer(1)
00443 {
00444 m_cItems = init_glob_(directory, pattern);
00445
00446 unixstl_assert((0 == m_cItems) || (NULL != m_base));
00447 }
00448
00449 inline glob_sequence::~glob_sequence() unixstl_throw_0()
00450 {
00451 unixstl_assert((0 == m_cItems) || (NULL != m_base));
00452
00453 if(NULL != m_base)
00454 {
00455 globfree(&m_glob);
00456 }
00457 }
00458
00459 inline us_size_t glob_sequence::size() const
00460 {
00461 return m_cItems;
00462 }
00463
00464 inline us_bool_t glob_sequence::empty() const
00465 {
00466 return 0 == size();
00467 }
00468
00469 inline glob_sequence::value_type const glob_sequence::operator [](glob_sequence::size_type index) const
00470 {
00471 unixstl_message_assert("index access out of range in glob_sequence", index < 1 + size());
00472
00473 return m_base[index];
00474 }
00475
00476 inline glob_sequence::const_iterator glob_sequence::begin() const
00477 {
00478 return m_base;
00479 }
00480
00481 inline glob_sequence::const_iterator glob_sequence::end() const
00482 {
00483 return m_base + m_cItems;
00484 }
00485
00486 #ifdef __STLSOFT_CF_BIDIRECTIONAL_ITERATOR_SUPPORT
00487 inline glob_sequence::const_reverse_iterator glob_sequence::rbegin() const
00488 {
00489 return const_reverse_iterator(end());
00490 }
00491
00492 inline glob_sequence::const_reverse_iterator glob_sequence::rend() const
00493 {
00494 return const_reverse_iterator(begin());
00495 }
00496 #endif
00497
00498 inline us_uint_t glob_sequence::validate_flags_(us_uint_t flags)
00499 {
00500 if(0 == (flags & (directories | files)))
00501 {
00502 flags |= (directories | files);
00503 }
00504
00505 if(0 == (flags & directories))
00506 {
00507 #ifndef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00508
00509
00510 flags |= includeDots;
00511
00512
00513
00514
00515 flags |= markDirs;
00516 #endif
00517 }
00518
00519 return flags;
00520 }
00521
00522 inline us_bool_t glob_sequence::is_end_of_path_elements_(glob_sequence::char_type const *pch, glob_sequence::difference_type index)
00523 {
00524 return pch[index] == '\0' ||
00525 ( pch[index + 1] == '\0' &&
00526 (
00527 #if defined(_UNIXSTL_COMPILER_IS_UNKNOWN) && \
00528 !defined(_UNIXSTL_GLOB_SEQUENCE_NO_BACK_SLASH_TERMINATOR)
00529 pch[index] == '\\' ||
00530 #endif
00531 pch[index] == '/'));
00532 }
00533
00534 inline us_bool_t glob_sequence::is_dots_maybe_slashed_(glob_sequence::char_type const *s, us_bool_t &bTwoDots)
00535 {
00536 unixstl_assert(NULL != s);
00537
00538 return s[0] == '.' &&
00539 ( (bTwoDots = false, is_end_of_path_elements_(s, 1)) ||
00540 (bTwoDots = true, ( s[1] == '.' &&
00541 is_end_of_path_elements_(s, 2))));
00542 }
00543
00544 inline us_size_t glob_sequence::init_glob_(glob_sequence::char_type const *directory, glob_sequence::char_type const *pattern)
00545 {
00546 unixstl_message_assert("Null pattern given to glob_sequence", NULL != pattern);
00547
00548 us_uint_t glob_flags = 0;
00549 basic_file_path_buffer<char_type> scratch_;
00550
00551 #ifndef __STLSOFT_CF_EXCEPTION_SUPPORT
00552 if(0 == scratch_.size())
00553 {
00554 m_base = NULL;
00555
00556 return 0;
00557 }
00558 #endif
00559
00560
00561 if( NULL != directory &&
00562 '\0' != *directory)
00563 {
00564
00565 if(absolutePath == (m_flags & absolutePath))
00566 {
00567 traits_type::get_full_path_name(directory, scratch_.size(), &scratch_[0]);
00568 }
00569 else
00570 {
00571 traits_type::str_copy(&scratch_[0], directory);
00572 }
00573
00574
00575 traits_type::ensure_dir_end(&scratch_[0]);
00576
00577
00578 traits_type::str_cat(&scratch_[0], pattern);
00579
00580 pattern = c_str_ptr(scratch_);
00581 }
00582
00583 if(m_flags & noSort)
00584 {
00585
00586 glob_flags |= GLOB_NOSORT;
00587 }
00588
00589 if(m_flags & markDirs)
00590 {
00591
00592 glob_flags |= GLOB_MARK;
00593 }
00594
00595 if(directories == (m_flags & (directories | files)))
00596 {
00597
00598 glob_flags |= GLOB_ONLYDIR;
00599 }
00600
00601 int gr = glob(pattern, glob_flags, NULL, &m_glob);
00602
00603 if(0 != gr)
00604 {
00605 #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT
00606 if(GLOB_NOMATCH != gr)
00607 {
00608 throw glob_sequence_exception(gr, 0);
00609 }
00610 #endif
00611
00612 m_base = NULL;
00613
00614 return 0;
00615 }
00616 else
00617 {
00618 char_type **base = m_glob.gl_pathv;
00619 us_size_t cItems = static_cast<us_size_t>(m_glob.gl_pathc);
00620
00621
00622
00623
00624 if( 0 == (m_flags & includeDots) ||
00625 #ifdef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00626 (m_flags & (directories | files)) != (directories | files))
00627 #else
00628 (m_flags & (directories | files)) == files)
00629 #endif
00630 {
00631 #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT
00632 try
00633 {
00634 m_buffer.resize(cItems);
00635 }
00636 catch(...)
00637 {
00638 globfree(&m_glob);
00639
00640 throw;
00641 }
00642 #else
00643 if(!m_buffer.resize(cItems))
00644 {
00645 globfree(&m_glob);
00646
00647 m_base = NULL;
00648
00649 return 0;
00650 }
00651 #endif
00652
00653 unixstl_assert(m_buffer.size() == cItems);
00654
00655 base = static_cast<char_type**>(memcpy(&m_buffer[0], base, m_buffer.size() * sizeof(char_type*)));
00656 }
00657
00658 if(0 == (m_flags & includeDots))
00659 {
00660
00661
00662
00663
00664
00665 us_bool_t foundDot1 = false;
00666 us_bool_t foundDot2 = false;
00667 char_type **begin = base;
00668 char_type **end = begin + cItems;
00669
00670 for(; begin != end; ++begin)
00671 {
00672 us_bool_t bTwoDots = false;
00673
00674 if(is_dots_maybe_slashed_(*begin, bTwoDots))
00675 {
00676
00677 if(begin != base)
00678 {
00679 unixstl_ns_qual_std(swap)(*begin, *base);
00680 }
00681 ++base;
00682 --cItems;
00683
00684 #ifndef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00685
00686 (bTwoDots ? foundDot2 : foundDot1) = true;
00687
00688 if( foundDot1 &&
00689 foundDot2)
00690 {
00691 break;
00692 }
00693 #endif
00694 }
00695 }
00696 }
00697
00698
00699
00700
00701 #ifdef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00702 if((m_flags & (directories | files)) != (directories | files))
00703 #else
00704 if((m_flags & (directories | files)) == files)
00705 #endif
00706 {
00707 basic_file_path_buffer<char_type> buffer;
00708 char_type **begin = base;
00709 char_type **end = begin + cItems;
00710
00711 #ifndef __STLSOFT_CF_EXCEPTION_SUPPORT
00712 if(0 == buffer.size())
00713 {
00714 globfree(&m_glob);
00715
00716 m_base = NULL;
00717
00718 return 0;
00719 }
00720 #endif
00721
00722 for(; begin != end; ++begin)
00723 {
00724
00725 struct stat st;
00726 int res;
00727 char_type const *entry = *begin;
00728
00729
00730 #ifndef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00731 unixstl_assert(files == (m_flags & (directories | files)));
00732
00733 if( 0 == (m_flags & markDirs) ||
00734 !traits_type::has_dir_end(entry))
00735 #endif
00736 {
00737 if(markDirs == (m_flags & markDirs))
00738 {
00739 traits_type::str_copy(&buffer[0], entry);
00740 traits_type::remove_dir_end(&buffer[0]);
00741 #if defined(__STLSOFT_COMPILER_IS_GCC) && \
00742 __GNUC__ < 3
00743 entry = buffer.c_str();
00744 #else
00745 entry = stlsoft_ns_qual(c_str_ptr)(buffer);
00746 #endif
00747 }
00748 res = stat(entry, &st);
00749
00750 if(0 != res)
00751 {
00752
00753
00754
00755
00756
00757 #if 0 // Can't decide on unequivocal list of error codes to exempt (exacerbated
00758
00759
00760 #ifdef __STLSOFT_CF_EXCEPTION_SUPPORT
00761 switch(errno)
00762 {
00763 case ENOENT:
00764 case ENOTDIR:
00765 # if defined(EACCESS)
00766 case EACCESS:
00767 # endif
00768 break;
00769 default:
00770 globfree(&m_glob);
00771 throw glob_sequence_exception(0, errno);
00772 break;
00773 }
00774 #endif
00775 #endif
00776 }
00777 else
00778 {
00779 #ifdef UNIXSTL_GLOB_SEQUENCE_ULTRA_CAUTIOUS
00780 if(m_flags & directories)
00781 {
00782 if(S_IFDIR == (st.st_mode & S_IFDIR))
00783 {
00784 continue;
00785 }
00786 }
00787 #endif
00788 if(m_flags & files)
00789 {
00790 if(S_IFREG == (st.st_mode & S_IFREG))
00791 {
00792 continue;
00793 }
00794 }
00795 }
00796 }
00797
00798
00799
00800
00801
00802
00803
00804
00805 unixstl_ns_qual_std(swap)(*begin, *base);
00806 ++base;
00807 --cItems;
00808 }
00809 }
00810
00811
00812 if( 0 == (m_flags & noSort) &&
00813 cItems != static_cast<us_size_t>(m_glob.gl_pathc))
00814 {
00815 unixstl_ns_qual_std(sort)(base, base + cItems);
00816 }
00817
00818
00819
00820
00821
00822 m_base = const_cast<char_type const **>(base);
00823
00824 return cItems;
00825 }
00826 }
00827
00828
00829
00831
00832
00833
00834
00835
00836
00837
00838
00839
00840
00841
00842 #endif
00843
00844
00845
00846
00847
00848