core/vul/vul_file_iterator.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_file_iterator.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 
00006 #include "vul_file_iterator.h"
00007 #include <vcl_string.h>
00008 #include <vcl_cassert.h>
00009 
00010 #include <vul/vul_file.h>
00011 #include <vul/vul_reg_exp.h>
00012 //:
00013 // \file
00014 // \verbatim
00015 //  Modifications:
00016 //   Ian Scott 09/06/2003 Add filename general globbing support
00017 // \endverbatim
00018 
00019 //: Declare pimpl, reset, and iteration routines for each OS
00020 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00021 
00022 #if defined(VCL_BORLAND_56)
00023 # include <stdint.h> /* for intptr_t on Borland 5.6. */
00024 #endif
00025 
00026 #include <io.h>
00027 
00028 struct vul_file_iterator_data
00029 {
00030   struct _finddata_t data_;
00031 # if defined VCL_VC_6 || defined VCL_VC_5 || defined VCL_BORLAND_55 || defined __MINGW32__
00032   typedef long handle_type;      // works with msvc6
00033 # else
00034   typedef intptr_t handle_type;  // not found by msvc6
00035 #endif
00036   handle_type handle_;
00037 
00038   vcl_string found_;
00039   char const* name_;
00040   vul_reg_exp reg_exp_;
00041   vcl_string original_dirname_;
00042 
00043   handle_type find_first(const char* dirname, struct _finddata_t* data)
00044   {
00045     return _findfirst(const_cast<char*>(dirname), data);
00046   }
00047 
00048   vul_file_iterator_data(char const* glob);
00049 
00050   void mkname() {
00051     // Remember full path
00052     found_ = original_dirname_ + "\\" + data_.name;
00053     name_ = found_.c_str();
00054     // no need to remember filename, it's in data_.name
00055   }
00056 
00057 
00058   void next() {
00059     assert(handle_ != 0);
00060     do
00061     {
00062       if (_findnext(handle_, &data_) != 0) {
00063         _findclose(handle_);
00064         handle_ = -1L;
00065         return;
00066       }
00067     } while ( ! reg_exp_.find(data_.name) );
00068     mkname();
00069   }
00070 
00071 
00072   // should be constish, and ret 0 when nuffink
00073   char const* value() {
00074     if (handle_ == -1L) return 0;
00075     return name_;
00076   }
00077 
00078   // Return non-dir part of fn
00079   char const* value_filename() {
00080     if (handle_ == -1L) return 0;
00081     return data_.name;
00082   }
00083 
00084   ~vul_file_iterator_data() {
00085     if (handle_ != -1L)
00086       _findclose(handle_);
00087   }
00088 };
00089 
00090 vul_file_iterator_data::vul_file_iterator_data(char const* glob)
00091 {
00092   original_dirname_ = vul_file::dirname(glob);
00093   handle_ = find_first((original_dirname_ + "\\*").c_str(), &data_);
00094 
00095   vcl_string baseglob = vul_file::basename(glob);
00096   vcl_string::iterator i = baseglob.begin();
00097   bool prev_slash=false, in_sqr_brackets=false;
00098   //assemble the Regexp string
00099   vcl_string re = "^"; // match the start of the string
00100   while (i != baseglob.end())
00101   {
00102     if (*i=='\\' && !prev_slash)
00103       prev_slash = true;
00104     else if (prev_slash)
00105     {
00106       prev_slash = false;
00107       re.append(1,('\\'));
00108       re.append(1,*i);
00109     }
00110     else if (*i=='[' && !in_sqr_brackets)
00111     {
00112       in_sqr_brackets = true;
00113       re.append(1,'[');
00114     }
00115     else if (*i==']' && in_sqr_brackets)
00116     {
00117       in_sqr_brackets = false;
00118       re.append(1,']');
00119     }
00120     else if (*i=='?' && !in_sqr_brackets)
00121       re.append(1,'.');
00122     else if (*i=='*' && !in_sqr_brackets)
00123       re.append(".*");
00124     else
00125       re.append(vul_reg_exp::protect(*i));
00126 
00127     ++i;
00128   }
00129   // match the end of the string
00130   re += '$';
00131 
00132   reg_exp_.compile(re.c_str());
00133 
00134 
00135   if (handle_ != -1L)
00136   {
00137     while ( ! reg_exp_.find(data_.name) )
00138     {
00139       if (_findnext(handle_, &data_) != 0) {
00140         _findclose(handle_);
00141         handle_ = -1L;
00142         return;
00143       }
00144     }
00145     mkname();
00146   }
00147 }
00148 
00149 #else // !defined(VCL_WIN32) || defined(__CYGWIN__)
00150 
00151 #include <dirent.h>
00152 
00153 struct vul_file_iterator_data
00154 {
00155   vcl_string original_dirname_;
00156   DIR* dir_handle_;
00157   dirent* de_;
00158   vcl_string found_;
00159   char const* name_;
00160   vul_reg_exp reg_exp_;
00161 
00162   vul_file_iterator_data(char const* glob);
00163 
00164   void mkname() {
00165     // Remember full path
00166     found_ = original_dirname_ + de_->d_name;
00167     name_ = found_.c_str();
00168     // no need to remember filename, it's in data_.name
00169   }
00170 
00171   void next() {
00172     // if dir_handle_ is NULL, then the directory probably doesn't
00173     // exist.
00174     if(dir_handle_ == 0) {
00175       return;
00176     }
00177     do
00178     {
00179       de_ = readdir(dir_handle_);
00180       if (de_==0) {
00181         closedir(dir_handle_);
00182         dir_handle_ = 0;
00183         return;
00184       }
00185     } while ( ! reg_exp_.find(de_->d_name) );
00186     mkname();
00187   }
00188 
00189   // should be constish, and ret 0 when nuffink
00190   char const* value() {
00191     if (!dir_handle_) return 0;
00192     return name_;
00193   }
00194 
00195   // Return non-dir part of fn
00196   char const* value_filename() {
00197     if (!dir_handle_) return 0;
00198     return de_->d_name;
00199   }
00200 
00201   ~vul_file_iterator_data() {
00202     if (dir_handle_)
00203       closedir(dir_handle_);
00204   }
00205 };
00206 
00207 vul_file_iterator_data::vul_file_iterator_data(char const* glob)
00208 {
00209   original_dirname_ = vul_file::dirname(glob) + "/";
00210 
00211   vcl_string baseglob = vul_file::basename(glob);
00212   vcl_string::iterator i = baseglob.begin();
00213   bool prev_slash=false, in_sqr_brackets=false;
00214   //assemble the Regexp string
00215   vcl_string re = "^"; // match the start of the string
00216   while (i != baseglob.end())
00217   {
00218     if (*i=='\\' && !prev_slash)
00219       prev_slash = true;
00220     else if (prev_slash)
00221     {
00222       prev_slash = false;
00223       re += '\\';
00224       re += *i;
00225     }
00226     else if (*i=='[' && !in_sqr_brackets)
00227     {
00228       in_sqr_brackets = true;
00229       re += '[';
00230     }
00231     else if (*i==']' && in_sqr_brackets)
00232     {
00233       in_sqr_brackets = false;
00234       re += ']';
00235     }
00236     else if (*i=='?' && !in_sqr_brackets)
00237       re += '.';
00238     else if (*i=='*' && !in_sqr_brackets)
00239       re += ".*";
00240     else
00241       re += vul_reg_exp::protect(*i);
00242 
00243     ++i;
00244   }
00245   // match the end of the string
00246   re += '$';
00247 
00248   reg_exp_.compile(re.c_str());
00249 
00250   dir_handle_ = opendir(original_dirname_.c_str());
00251 
00252   next();
00253 }
00254 
00255 #endif // !defined(VCL_WIN32) || defined(__CYGWIN__)
00256 
00257 // -----------------------------------------------------------------------------
00258 
00259 vul_file_iterator::vul_file_iterator(char const* glob)
00260 {
00261   p = 0;
00262   reset(glob);
00263 }
00264 
00265 vul_file_iterator::vul_file_iterator(vcl_string const& glob)
00266 {
00267   p = 0;
00268   reset(glob.c_str());
00269 }
00270 
00271 vul_file_iterator::~vul_file_iterator()
00272 {
00273   delete p;
00274 }
00275 
00276 void vul_file_iterator::reset(char const* glob)
00277 {
00278   delete p;
00279   p = new vul_file_iterator_data(glob);
00280 }
00281 
00282 char const* vul_file_iterator::operator()()
00283 {
00284   return p->value();
00285 }
00286 
00287 char const* vul_file_iterator::filename()
00288 {
00289   return p->value_filename();
00290 }
00291 
00292 vul_file_iterator::operator vul_file_iterator::safe_bool() const
00293 {
00294   return (p->value() != 0)? VCL_SAFE_BOOL_TRUE : 0;
00295 }
00296 
00297 bool vul_file_iterator::operator!() const
00298 {
00299   return (p->value() != 0)? false : true;
00300 }
00301 
00302 vul_file_iterator& vul_file_iterator::operator++()
00303 {
00304   p->next();
00305   return *this;
00306 }