core/vul/vul_file.cxx
Go to the documentation of this file.
00001 // This is core/vul/vul_file.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author Andrew W. Fitzgibbon, Oxford RRG
00008 // \date   02 Nov 1998
00009 //
00010 // \verbatim
00011 //  Modifications
00012 //   08 Jan 2009  Peter Vanroose- simplified "delete_file_glob()" implementation
00013 // \endverbatim
00014 //
00015 //-----------------------------------------------------------------------------
00016 
00017 #include "vul_file.h"
00018 
00019 #include <sys/stat.h>
00020 #include <vcl_cstring.h>
00021 #include <vcl_cctype.h>
00022 #include <vcl_cstdlib.h>
00023 
00024 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00025 #include <direct.h> // for getcwd, mkdir
00026 #if defined(VCL_VC_8)
00027 #define getcwd _getcwd // getcwd is now "deprecated" by Visual Studio
00028 #define chdir  _chdir  // idem
00029 #define mkdir  _mkdir  // idem
00030 #endif
00031 #else
00032 #include <unistd.h>
00033 #endif
00034 
00035 #if defined(como4301) && defined(__linux__)
00036 # ifndef S_IFMT
00037 #  define S_IFMT 0170000
00038 # endif
00039 # ifndef S_IFDIR
00040 #  define S_IFDIR 0040000
00041 # endif
00042 #endif
00043 
00044 #include <vul/vul_user_info.h>
00045 
00046 vcl_string vul_file::get_cwd()
00047 {
00048   const int BIG = 65536;
00049   char buf[BIG];
00050   if (getcwd(buf,BIG-1))
00051     return buf;
00052   else
00053     return "Error returned by getcwd";
00054 }
00055 
00056 bool vul_file::change_directory(char const* dirname)
00057 {
00058   return 0 == chdir(dirname);
00059 }
00060 
00061 bool vul_file::make_directory(char const* name)
00062 {
00063 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00064   return -1 != mkdir(name);
00065 #else
00066   return -1 != mkdir(name, 0755);
00067 #endif
00068 }
00069 
00070 bool vul_file::is_directory(char const* fn)
00071 {
00072   struct stat fs;
00073   return stat(fn, &fs) == 0
00074       && (fs.st_mode & S_IFMT) == S_IFDIR;
00075 }
00076 
00077 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00078 bool vul_file::is_drive(char const* fn)
00079 {
00080   // a drive string looks like "c:", "z:"
00081   return fn
00082       && vcl_isalpha(fn[0])
00083       && fn[1]==':'
00084       && fn[2]=='\0';
00085 }
00086 #endif
00087 
00088 //: Make a writable directory, including any necessary parents.
00089 // Returns true if successful, or if the directory already exists.
00090 // Implemented by calling itself recursively on the parent directory.
00091 bool vul_file::make_directory_path(char const* filename)
00092 {
00093 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00094   if (is_directory(filename) || is_drive(filename)) return true;
00095 #else
00096   if (is_directory(filename)) return true;
00097 #endif
00098   // You can get a race condition here if there are multiple
00099   // process/threads trying to make the same dir at the same time
00100   // So if the make_directory fails, just check that someone else
00101   // didn't make it in the intervening time.
00102   return make_directory_path(dirname(filename))
00103       && (make_directory(filename) || is_directory(filename));
00104 }
00105 
00106 
00107 unsigned long vul_file::size(char const* fn)
00108 {
00109   struct stat fs;
00110   if (stat(fn, &fs) == 0)
00111     return fs.st_size;
00112   else
00113     return 0L;
00114 }
00115 
00116 bool vul_file::exists(char const* fn)
00117 {
00118   struct stat fs;
00119   vcl_string name(fn);
00120 
00121 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00122   vcl_string::size_type last_non_slash_index = name.find_last_not_of("\\/");
00123 #else
00124   vcl_string::size_type last_non_slash_index = name.find_last_not_of('/');
00125 #endif
00126   if (last_non_slash_index != vcl_string::npos)
00127     last_non_slash_index++;
00128   name = name.substr(0, last_non_slash_index);
00129   return stat(name.c_str(), &fs) == 0;
00130 }
00131 
00132 vcl_string vul_file::dirname(char const* fn)
00133 {
00134   vcl_string self(fn);
00135 
00136 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00137   vcl_string::size_type slash_index = self.find_last_of("\\/");
00138 #else
00139   vcl_string::size_type slash_index = self.rfind('/');
00140 #endif
00141   if (slash_index == vcl_string::npos)
00142     return ".";
00143 
00144 
00145   return self.substr(0, slash_index);
00146 }
00147 
00148 vcl_string vul_file::extension(char const* fn)
00149 {
00150   vcl_string self(fn);
00151 
00152   vcl_string::size_type dot_index = self.rfind('.');
00153   if (dot_index != vcl_string::npos)
00154     return self.substr(dot_index, vcl_string::npos);
00155   else
00156     return vcl_string();
00157 }
00158 
00159 vcl_string vul_file::strip_directory(char const* fn)
00160 {
00161   vcl_string self(fn);
00162 
00163 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00164   vcl_string::size_type slash_index = self.find_last_of("\\/");
00165 #else
00166   vcl_string::size_type slash_index = self.rfind('/');
00167 #endif
00168   if (slash_index != vcl_string::npos)
00169     self.erase(0, slash_index+1);
00170 
00171   return self;
00172 }
00173 
00174 vcl_string vul_file::strip_extension(char const* fn)
00175 {
00176   vcl_string self(fn);
00177 
00178   vcl_string::size_type dot_index = self.rfind('.');
00179   if (dot_index != vcl_string::npos)
00180     self.erase(dot_index, vcl_string::npos);
00181 
00182   return self;
00183 }
00184 
00185 vcl_string vul_file::basename(char const* fn, char const * suffix)
00186 {
00187   // First strip dir
00188   vcl_string self(fn);
00189 
00190 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00191   vcl_string::size_type slash_index = self.find_last_of("\\/");
00192 #else
00193   vcl_string::size_type slash_index = self.rfind('/');
00194 #endif
00195 
00196   if (slash_index != vcl_string::npos)
00197     self.erase(0, slash_index+1);
00198 
00199   // Now strip suffix if any
00200   if (suffix) {
00201     int start = (int)(self.size() - vcl_strlen(suffix));
00202     if (start >= 0)
00203       // egcs, 2.95, 2.96 have no method which can do
00204       //   self.compare(start, vcl_string::npos, suffix) == 0
00205       if (vcl_string(self.begin()+start, self.end()) == suffix)
00206         self.erase(start, vcl_string::npos);
00207   }
00208   return self;
00209 }
00210 
00211 
00212 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00213 //: replace instances of 'from' in 's' with 'to'
00214 static unsigned replace(char from, char to, vcl_string &s)
00215 {
00216   unsigned c = 0;
00217   for (unsigned i=0; i<s.size(); ++i)
00218     if (s[i] == from)
00219     {
00220       c++;
00221       s[i] = to;
00222     }
00223     return c;
00224 }
00225 #endif
00226 
00227 //: Delete 1 or more files using the Local OS preferred globbing.
00228 // E.g. \c delete_file_glob("*"); will delete all the files in the
00229 // current directory on most operating systems.
00230 // Takes Posix path separators i.e. '/'
00231 bool vul_file::delete_file_glob(vcl_string const& file_glob)
00232 {
00233 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00234   vcl_string command = file_glob;
00235   replace('/', '\\', command);
00236   command = "del /Q " + command;
00237 #else
00238   vcl_string command = "/bin/rm -f " + file_glob;
00239 #endif
00240   return vcl_system(command.c_str())==0;
00241 }
00242 
00243 
00244 vcl_string vul_file::expand_tilde(char const* vul_filename)
00245 {
00246   if (!vul_filename || (vcl_strlen(vul_filename) == 0))
00247     return "";
00248 
00249 #if defined(VCL_WIN32) && !defined(__CYGWIN__)
00250   // ~ meaningless on win32
00251   return vcl_string(vul_filename);
00252 #else
00253 
00254   if (vul_filename[0] != '~')
00255     return vcl_string(vul_filename);
00256 
00257   //// ** Have a tilde, go for it
00258 
00259   // 1. Strip to directory only, and remove the tilde itself
00260   vcl_string fn(vul_filename);
00261   vcl_string dir;
00262   vcl_string::size_type first_slash =  fn.find('/');
00263   if (first_slash != vcl_string::npos) {
00264     dir = fn.substr(1, first_slash-1);
00265     fn = fn.substr(first_slash, vcl_string::npos);
00266   }
00267   else {
00268     dir = fn.substr(1, vcl_string::npos);
00269     fn = "";
00270   }
00271   // Now, from original to  (dir, vul_filename) is one of
00272   //  ~            ""     ""
00273   //  ~fre         "fre"  ""
00274   //  ~/fred       ""     "/fred"
00275   //  ~user/fred   "user" "/fred"
00276 
00277   if (dir.size() == 0) {
00278     // Was just ~, use getenv(HOME)
00279     char const * home_directory = getenv("HOME");
00280     if (!home_directory) home_directory = "";
00281     return vcl_string(home_directory) + fn;
00282   }
00283 
00284   // Was ~user, Check password list for match
00285   vul_user_info user(dir);
00286   if (!user.ok)
00287     return vcl_string(vul_filename);
00288 
00289   // Got user info
00290   return user.home_directory + fn;
00291 #endif
00292 }
00293 
00294 
00295 #if defined(VCL_WIN32) && VXL_USE_WIN_WCHAR_T
00296 #  include <vcl_cwchar.h>
00297 
00298 std::wstring
00299 vul_file::get_cwd(wchar_t* /*dummy*/)
00300 {
00301   const int BIG = 65536;
00302   wchar_t buf[BIG];
00303   buf[0] = L'\0';
00304   _wgetcwd(buf,BIG-1);
00305   return buf;
00306 }
00307 
00308 bool vul_file::change_directory(wchar_t const* dirname)
00309 {
00310   return 0 == _wchdir(dirname);
00311 }
00312 
00313 bool vul_file::make_directory(wchar_t const* name)
00314 {
00315   return -1 != _wmkdir(name);
00316 }
00317 
00318 bool vul_file::is_directory(wchar_t const* fn)
00319 {
00320   struct _stat fs;
00321   return _wstat(fn, &fs) == 0
00322       && (fs.st_mode & S_IFMT) == S_IFDIR;
00323 }
00324 
00325 bool vul_file::is_drive(wchar_t const* fn)
00326 {
00327   // a drive string looks like "c:", "z:"
00328   return fn
00329       && iswalpha(fn[0])
00330       && fn[1]==L':'
00331       && fn[2]==L'\0';
00332 }
00333 
00334 //: Make a writable directory, including any necessary parents.
00335 // Returns true if successful, or if the directory already exists.
00336 bool vul_file::make_directory_path(wchar_t const* filename)
00337 {
00338   if (is_directory(filename) || is_drive(filename)) return true;
00339 
00340   return make_directory_path(dirname(filename))
00341       && make_directory(filename);
00342 }
00343 
00344 bool vul_file::exists(wchar_t const* fn)
00345 {
00346   struct _stat fs;
00347   return _wstat(fn, &fs) == 0;
00348 }
00349 
00350 std::wstring vul_file::dirname(wchar_t const* fn)
00351 {
00352   std::wstring self(fn);
00353 
00354   std::wstring::size_type slash_index = self.find_last_of(L"\\/");
00355   if (slash_index == std::wstring::npos)
00356     return L".";
00357 
00358   return self.substr(0, slash_index);
00359 }
00360 
00361 std::wstring vul_file::extension(wchar_t const* fn)
00362 {
00363   std::wstring self(fn);
00364 
00365   std::wstring::size_type dot_index = self.rfind(L'.');
00366   if (dot_index != std::wstring::npos)
00367     return self.substr(dot_index, std::wstring::npos);
00368   else
00369     return std::wstring();
00370 }
00371 
00372 std::wstring vul_file::strip_directory(wchar_t const* fn)
00373 {
00374   std::wstring self(fn);
00375 
00376   std::wstring::size_type slash_index = self.find_last_of(L"\\/");
00377   if (slash_index != std::wstring::npos)
00378     self.erase(0, slash_index+1);
00379 
00380   return self;
00381 }
00382 
00383 std::wstring vul_file::strip_extension(wchar_t const* fn)
00384 {
00385   std::wstring self(fn);
00386 
00387   std::wstring::size_type dot_index = self.rfind(L'.');
00388   if (dot_index != std::wstring::npos)
00389     self.erase(dot_index, std::wstring::npos);
00390 
00391   return self;
00392 }
00393 
00394 std::wstring vul_file::basename(wchar_t const* fn, wchar_t const * suffix)
00395 {
00396   // First strip dir
00397   std::wstring self(fn);
00398 
00399   std::wstring::size_type slash_index = self.find_last_of(L"\\/");
00400 
00401   if (slash_index != std::wstring::npos)
00402     self.erase(0, slash_index+1);
00403 
00404   // Now strip suffix if any
00405   if (suffix) {
00406     int start = (int)self.size() - (int)wcslen(suffix);
00407     if (start >= 0)
00408       // egcs, 2.95, 2.96 have no method which can do
00409       //   self.compare(start, std::wstring::npos, suffix) == 0
00410       if (std::wstring(self.begin()+start, self.end()) == suffix)
00411         self.erase(start, std::wstring::npos);
00412   }
00413   return self;
00414 }
00415 
00416 #endif
00417