dir_cursor.h

00001 /*
00002  * ASTL - the Automaton Standard Template Library.
00003  * C++ generic components for Finite State Automata handling.
00004  * Copyright (C) 2000-2003 Vincent Le Maout (vincent.lemaout@chello.fr).
00005  * 
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  * 
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  * 
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  */
00021 
00022 #ifndef ASTL_DIR_CURSOR_H
00023 #define ASTL_DIR_CURSOR_H
00024 
00025 // not implemented for Visual C++
00026 #ifndef _MSC_VER
00027 
00028 #include <astl.h>
00029 #include <sys/types.h>
00030 #include <sys/stat.h>
00031 #include <unistd.h>
00032 #include <dirent.h>
00033 #include <string>
00034 #include <cstring>
00035 #include <climits>
00036 #include <functional>
00037 
00038 using namespace std;
00039 
00040 namespace astl {
00041 
00042 // A directory cursor simulates an automaton from a directory tree:
00043 // transitions are labeled with files names and a predicate provided
00044 // at instanciation time dictates if a state is a terminal state. By
00045 // default, a state is considered non-terminal if it is a directory. 
00046 struct default_predicate 
00047   : public binary_function<string, struct stat *, bool>
00048 {
00049   bool operator()(const string &, const struct stat *s) const {
00050     return !S_ISDIR(s->st_mode);
00051   }
00052 };
00053 
00054 template <class Predicate = default_predicate>
00055 class directory_cursor : public forward_cursor_concept
00056 {
00057 protected:
00058   string state, transition;   // current state and letter
00059   DIR *dir;
00060 
00061 public:
00062   typedef directory_cursor self;
00063   typedef time_t           tag_type;    // time of last modification
00064   typedef string           state_type;
00065   typedef string           char_type;
00066 
00067   typedef std::char_traits<string> char_traits;
00068 
00069   directory_cursor() 
00070         : dir(NULL)
00071   { }
00072   
00073   directory_cursor(const string &dir_)
00074     : state(dir_) {
00075     dir = opendir(state.c_str());
00076   }
00077 
00078   directory_cursor(const self &x)
00079     : state(x.state), transition(x.transition), dir(x.dir) {
00080     if (x.dir) {
00081       dir = opendir(state.c_str());
00082       if (!transition.empty())
00083         seekdir(dir, telldir(x.dir));
00084     }
00085   }
00086 
00087   ~directory_cursor() { if (dir) closedir(dir); }
00088 
00089   state_type src() const { return state; }
00090 
00091   self& operator=(const state_type& p) 
00092   { 
00093     state = p;
00094     if (dir) closedir(dir);
00095     dir = opendir(state.c_str());
00096     return *this;
00097   }
00098 
00099   bool sink() const { return state.empty(); }
00100 
00101   bool forward(const char_type &a)   // linear time method
00102   { 
00103     struct dirent *entry;
00104     for(rewinddir(dir); (entry = readdir(dir)) != NULL; )
00105       if (strcmp(a.c_str(), entry->d_name)) {
00106         state += '/';
00107         state += entry->d_name;
00108         closedir(dir);
00109         dir = opendir(state.c_str());
00110         return true;
00111       }
00112     closedir(dir);
00113     dir = NULL;
00114     state.clear();
00115     return false;
00116   }
00117 
00118   bool src_final() const
00119   { 
00120     struct stat s;
00121     stat(state.c_str(), &s);
00122     return Predicate()(state, &s);
00123   }
00124 
00125   tag_type src_tag() const { 
00126     struct stat s;
00127     stat(state.c_str(), &s);
00128     return s.st_mtime;
00129   }
00130     
00131   bool exists(const char_type &a) const {
00132     struct dirent *tmp_entry = NULL;
00133     DIR *d = opendir(state.c_str());
00134     if (d) {
00135       for(rewinddir(d); (tmp_entry = readdir(d)) != NULL; )
00136         if (strcmp(a.c_str(), tmp_entry->d_name)) break;
00137       
00138       closedir(d);
00139     }
00140     return tmp_entry != NULL;
00141   }
00142 
00143   self& operator=(const self &x) { 
00144     if (dir) closedir(dir);
00145     state = x.state;
00146     transition = x.transition;
00147     dir = opendir(state.c_str());
00148     if (dir && !transition.empty()) seekdir(dir, telldir(x.dir));
00149     return *this;
00150   }  
00151 
00152   bool operator==(const self &x) const { 
00153           return state == x.state && transition == x.transition; 
00154   }
00155 
00156   char_type letter() const { return transition; }
00157 
00158   bool first() { 
00159     if (dir == NULL) return false;
00160     struct dirent *entry;
00161     for(rewinddir(dir); (entry = readdir(dir)) != NULL; )
00162       if (strcmp(".", entry->d_name) != 0 && strcmp("..", entry->d_name) != 0) {
00163         transition = entry->d_name;
00164         return true;
00165       }
00166     return false;
00167   }
00168   
00169   bool next() { 
00170     struct dirent *entry;
00171     for(; (entry = readdir(dir)) != NULL; )
00172       if (strcmp(".", entry->d_name) != 0 || strcmp("..", entry->d_name) != 0) {
00173         transition = entry->d_name;
00174         return true;
00175       }
00176     return false;
00177   }
00178 
00179   void forward() { 
00180     state += '/';
00181     state += transition;
00182     closedir(dir);
00183     dir = opendir(state.c_str());
00184   }
00185 
00186   bool find(const char_type &a) { 
00187     if (dir == NULL) return false;
00188     struct dirent *entry;
00189     for(rewinddir(dir); (entry = readdir(dir)) != NULL; )
00190       if (strcmp(a.c_str(), entry->d_name)) {
00191         transition = entry->d_name;
00192         return true;
00193       }
00194     return false;
00195   }
00196 
00197   state_type aim() const { 
00198     return state + "/" + transition;
00199   }
00200 
00201   bool aim_final() const { 
00202     struct stat s;
00203     string path = aim();
00204     stat(path.c_str(), &s);
00205     return Predicate()(path, &s);
00206   }
00207 
00208   tag_type aim_tag() const {
00209     struct stat s;
00210     string path = aim();
00211     stat(path.c_str(), &s);
00212     return s.st_mtime; 
00213   }
00214 };
00215 
00216 inline
00217 directory_cursor<> directoryc(const string &d = ".") {
00218   return directory_cursor<>(d);
00219 }
00220 
00221 template <typename Predicate>
00222 inline
00223 directory_cursor<Predicate> 
00224 directoryc(const Predicate&, const string &d = ".") {
00225   return directory_cursor<Predicate>(d);
00226 }
00227 
00228 #endif
00229 
00230 } // namespace astl
00231 
00232 #endif 

Generated on Sun Mar 8 02:41:33 2009 for ASTL by  doxygen 1.5.7.1