00001 /** 00002 \file Robots/LoBot/util/LoFile.C 00003 \brief Definitions of functions defined in LoFile.H 00004 */ 00005 00006 // //////////////////////////////////////////////////////////////////// // 00007 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00008 // by the University of Southern California (USC) and the iLab at USC. // 00009 // See http://iLab.usc.edu for information about this project. // 00010 // //////////////////////////////////////////////////////////////////// // 00011 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00012 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00013 // in Visual Environments, and Applications'' by Christof Koch and // 00014 // Laurent Itti, California Institute of Technology, 2001 (patent // 00015 // pending; application number 09/912,225 filed July 23, 2001; see // 00016 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00017 // //////////////////////////////////////////////////////////////////// // 00018 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00019 // // 00020 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00021 // redistribute it and/or modify it under the terms of the GNU General // 00022 // Public License as published by the Free Software Foundation; either // 00023 // version 2 of the License, or (at your option) any later version. // 00024 // // 00025 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00026 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00027 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00028 // PURPOSE. See the GNU General Public License for more details. // 00029 // // 00030 // You should have received a copy of the GNU General Public License // 00031 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00032 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00033 // Boston, MA 02111-1307 USA. // 00034 // //////////////////////////////////////////////////////////////////// // 00035 // 00036 // Primary maintainer for this file: mviswana usc edu 00037 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/util/LoFile.C $ 00038 // $Id: LoFile.C 14083 2010-09-30 13:59:37Z mviswana $ 00039 // 00040 00041 //-------------------------- BOOST-BASED API ---------------------------- 00042 00043 #ifdef INVT_HAVE_BOOST_FILESYSTEM 00044 00045 // lobot headers 00046 #include "Robots/LoBot/util/LoFile.H" 00047 00048 // Boost headers 00049 #include <boost/filesystem/operations.hpp> 00050 00051 // Standard C++ headers 00052 #include <algorithm> 00053 #include <deque> 00054 #include <functional> 00055 #include <iterator> 00056 00057 namespace lobot { 00058 00059 // File/path name manipulations 00060 std::string dirname(const std::string& path) 00061 { 00062 namespace fs = boost::filesystem ; 00063 return fs::path(path).branch_path().string() ; 00064 } 00065 00066 std::string basename(const std::string& path) 00067 { 00068 namespace fs = boost::filesystem ; 00069 return fs::path(path).leaf() ; 00070 } 00071 00072 // File/path name tests 00073 bool exists(const std::string& path) 00074 { 00075 namespace fs = boost::filesystem ; 00076 return fs::exists(fs::path(path)); 00077 } 00078 00079 bool is_dir(const std::string& path) 00080 { 00081 namespace fs = boost::filesystem ; 00082 fs::path p(path) ; 00083 return fs::exists(p) && fs::is_directory(p) ; 00084 } 00085 00086 bool is_file(const std::string& path) 00087 { 00088 return !is_dir(path) ; 00089 } 00090 00091 // Directory operations 00092 std::vector<std::string> list_dir(const std::string& path) 00093 { 00094 namespace fs = boost::filesystem ; 00095 fs::path p(path) ; 00096 std::vector<std::string> ls ; 00097 std::transform(fs::directory_iterator(p), fs::directory_iterator(), 00098 std::back_inserter(ls), std::mem_fun_ref(&fs::path::string)); 00099 return ls ; 00100 } 00101 00102 } // end of namespace encapsulating above definitions 00103 00104 #else // Boost.Filesystem not available 00105 00106 //-------------------------- UNIX-BASED API ----------------------------- 00107 00108 // lobot headers 00109 #include "Robots/LoBot/util/LoFile.H" 00110 #include "Robots/LoBot/util/LoSysConf.H" 00111 00112 // Standard C++ headers 00113 #include <algorithm> 00114 #include <deque> 00115 #include <iterator> 00116 00117 // Standard C headers 00118 #include <stdlib.h> 00119 #include <stddef.h> 00120 00121 // Unix headers 00122 #include <libgen.h> 00123 #include <dirent.h> 00124 #include <sys/stat.h> 00125 #include <sys/types.h> 00126 00127 // Helper function to copy an std::string to a dynamically allocated char 00128 // array. The client must delete the char array returned by this 00129 // function. 00130 static char* dup_string(const std::string& s) 00131 { 00132 const int N = s.size() ; 00133 char* tmp = new char[N + 1] ; 00134 std::copy(s.begin(), s.end(), tmp) ; 00135 tmp[N] = '\0' ; 00136 return tmp ; 00137 } 00138 00139 namespace lobot { 00140 00141 // File/path name manipulations 00142 std::string dirname(const std::string& path) 00143 { 00144 char* tmp = dup_string(path) ; 00145 std::string dname = ::dirname(tmp) ; 00146 delete[] tmp ; 00147 return dname ; 00148 } 00149 00150 std::string basename(const std::string& path) 00151 { 00152 char* tmp = dup_string(path) ; 00153 std::string bname = ::basename(tmp) ; 00154 delete[] tmp ; 00155 return bname ; 00156 } 00157 00158 // File/path name tests 00159 bool exists(const std::string& path) 00160 { 00161 struct stat buf ; 00162 return stat(path.c_str(), &buf) == 0 ; 00163 } 00164 00165 bool is_dir(const std::string& path) 00166 { 00167 struct stat buf ; 00168 return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode) ; 00169 } 00170 00171 bool is_file(const std::string& path) 00172 { 00173 struct stat buf ; 00174 return stat(path.c_str(), &buf) == 0 && S_ISREG(buf.st_mode) ; 00175 } 00176 00177 // Directory operations 00178 // 00179 // DEVNOTE: This code is adapted from Marc J. Rochkind's "Advanced Unix 00180 // Programming." See chapter 3 (Advanced File I/O), section 3.6.1: 00181 // Reading Directories. 00182 std::vector<std::string> list_dir(const std::string& path) 00183 { 00184 typedef std::vector<std::string> list ; 00185 00186 const int N = maxlen_filename(path.c_str()) ; 00187 struct dirent* input = reinterpret_cast<struct dirent*>( 00188 malloc(offsetof(struct dirent, d_name) + N + 1)) ; 00189 if (input == NULL) // gave it our best shot, but now system is out of memory 00190 return list() ; 00191 00192 DIR* dir = opendir(path.c_str()) ; 00193 if (dir == NULL) { // couldn't open directory for reading 00194 free(input) ; 00195 return list() ; 00196 } 00197 00198 list ls ; 00199 for(;;) 00200 { 00201 struct dirent* output = NULL ; 00202 readdir_r(dir, input, &output) ; 00203 if (output == NULL) // error or end of directory entries 00204 break ; 00205 00206 std::string file_name = output->d_name ; 00207 if (file_name == "." || file_name == "..") 00208 continue ; 00209 ls.push_back(path + "/" + file_name) ; 00210 } 00211 00212 closedir(dir) ; 00213 free(input) ; 00214 return ls ; 00215 } 00216 00217 } // end of namespace encapsulating above functions 00218 00219 #endif // INVT_HAVE_BOOST_FILESYSTEM 00220 00221 //-------------------------- BOOST-BASED API ---------------------------- 00222 00223 #ifdef INVT_HAVE_BOOST_REGEX 00224 00225 #include <boost/regex.hpp> 00226 00227 // Helper function to perform an exact string match between name and target 00228 static bool match_exact(const std::string& name, const std::string& target) 00229 { 00230 return name == target ; 00231 } 00232 00233 namespace lobot { 00234 00235 // Helper function object to perform regular expression matching between 00236 // name and target. 00237 // 00238 // NOTE: The function call operator will be passed two parameters, viz., 00239 // name and target (just like match_exact). However, we do not use the 00240 // second parameter, viz., target, because it is expected to be a regular 00241 // expression, which we would have compiled during instantiation. 00242 // Therefore, the function call operator compares against the precompiled 00243 // regex rather than the supplied target parameter. 00244 // 00245 // DEVNOTE: Even though the function call operator ignores its second 00246 // parameter, it must nonetheless be accepted because this function 00247 // object is used in conjunction with find_helper(), which expects its 00248 // matching predicate to take two parameters. 00249 class match_regex { 00250 boost::regex m_regex ; 00251 public: 00252 match_regex(const std::string& pattern) ; 00253 bool operator()(const std::string& name, const std::string&) const { 00254 return boost::regex_search(name, m_regex) ; 00255 } 00256 } ; 00257 00258 match_regex::match_regex(const std::string& pattern) 00259 : m_regex(pattern) 00260 {} 00261 00262 // Return list of all files or directories under given directory using 00263 // the given predicate to match file names against the supplied target 00264 // pattern. 00265 template<typename pred> 00266 static std::vector<std::string> 00267 find_helper(const std::string& dir, const std::string& target, 00268 pred match, bool (*is_type)(const std::string&)) 00269 { 00270 typedef std::vector<std::string> list ; 00271 if (! is_dir(dir)) 00272 return list() ; 00273 00274 list matches ; 00275 std::deque <std::string> fringe ; // queue of unexplored items 00276 fringe.push_back(dir) ; 00277 00278 while (! fringe.empty()) 00279 { 00280 std::string item = fringe.front() ; 00281 fringe.pop_front() ; 00282 00283 if (is_dir(item)) { 00284 list ls = list_dir(item) ; 00285 std::copy(ls.begin(), ls.end(), std::back_inserter(fringe)) ; 00286 } 00287 00288 if (is_type(item) && match(item, target)) 00289 matches.push_back(item) ; 00290 } 00291 std::sort(matches.begin(), matches.end()) ; 00292 return matches ; 00293 } 00294 00295 // Return list of all files under given directory matching specified name 00296 std::vector<std::string> 00297 find_file(const std::string& dir, const std::string& target) 00298 { 00299 try 00300 { 00301 return find_helper(dir, target, match_regex(target), is_file) ; 00302 } 00303 catch (boost::regex_error&){} 00304 return find_helper(dir, target, match_exact, is_file) ; 00305 } 00306 00307 // Return list of all subdirectories of given directory matching specified name 00308 std::vector<std::string> 00309 find_dir(const std::string& dir, const std::string& target) 00310 { 00311 try 00312 { 00313 return find_helper(dir, target, match_regex(target), is_dir) ; 00314 } 00315 catch (boost::regex_error&){} 00316 return find_helper(dir, target, match_exact, is_dir) ; 00317 } 00318 00319 } // end of namespace lobot 00320 00321 #else // Boost.Regex not available 00322 00323 //-------------------------- UNIX-BASED API ----------------------------- 00324 00325 #include <regex.h> 00326 00327 // Helper function to perform an exact string match between name and target 00328 static bool 00329 match_exact(const std::string& name, const std::string& target, const regex_t*) 00330 { 00331 return name == target ; 00332 } 00333 00334 // Helper function to match given name against a regular expression 00335 static bool 00336 match_regex(const std::string& name, const std::string&, const regex_t* regex) 00337 { 00338 return regexec(regex, name.c_str(), 0, 0, 0) == 0 ; 00339 } 00340 00341 namespace lobot { 00342 00343 // Return list of all files or directories under given directory matching 00344 // specified name. 00345 static std::vector<std::string> 00346 find_helper(const std::string& dir, const std::string& target, 00347 bool (*is_type)(const std::string&)) 00348 { 00349 typedef std::vector<std::string> list ; 00350 if (! is_dir(dir)) 00351 return list() ; 00352 00353 typedef bool (*MatchFunc)(const std::string&, 00354 const std::string&, const regex_t*) ; 00355 MatchFunc match = match_exact ; 00356 00357 regex_t regex ; 00358 if (regcomp(®ex, target.c_str(), 00359 REG_EXTENDED | REG_NOSUB | REG_NEWLINE) == 0) 00360 match = match_regex ; 00361 00362 list matches ; 00363 std::deque<std::string> fringe ; // queue of unexplored items 00364 fringe.push_back(dir) ; 00365 00366 while (! fringe.empty()) 00367 { 00368 std::string item = fringe.front() ; 00369 fringe.pop_front() ; 00370 00371 if (is_dir(item)) { 00372 list ls = list_dir(item) ; 00373 std::copy(ls.begin(), ls.end(), std::back_inserter(fringe)) ; 00374 } 00375 00376 if (is_type(item) && match(item, target, ®ex)) 00377 matches.push_back(item) ; 00378 } 00379 00380 if (match == match_regex) 00381 regfree(®ex) ; 00382 00383 std::sort(matches.begin(), matches.end()) ; 00384 return matches ; 00385 } 00386 00387 // Return list of files under given directory matching specified name 00388 std::vector<std::string> 00389 find_file(const std::string& dir, const std::string& target) 00390 { 00391 return find_helper(dir, target, is_file) ; 00392 } 00393 00394 // Return list of subdirectories under given directory matching specified name 00395 std::vector<std::string> 00396 find_dir(const std::string& dir, const std::string& target) 00397 { 00398 return find_helper(dir, target, is_dir) ; 00399 } 00400 00401 } // end of namespace lobot 00402 00403 #endif // INVT_HAVE_BOOST_REGEX 00404 00405 //---------------------- COMMON IMPLEMENTATIONS ------------------------- 00406 00407 // These functions are identical regardless of whether we use Boost or 00408 // the Unix API. 00409 namespace lobot { 00410 00411 // Return the file name's extension 00412 std::string extension(const std::string& path) 00413 { 00414 std::string base_name = basename(path) ; 00415 return base_name.substr(base_name.find('.') + 1) ; 00416 } 00417 00418 } // end of namespace lobot 00419 00420 //----------------------------------------------------------------------- 00421 00422 /* So things look consistent in everyone's emacs... */ 00423 /* Local Variables: */ 00424 /* indent-tabs-mode: nil */ 00425 /* End: */