BASIS  r3148
os.cxx
Go to the documentation of this file.
00001 /**
00002  * @file  os.cxx
00003  * @brief Operating system dependent functions.
00004  *
00005  * Copyright (c) 2011 University of Pennsylvania. All rights reserved.<br />
00006  * See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00007  *
00008  * Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00009  */
00010 
00011 
00012 #include <basis/config.h> // platform macros - must be first
00013 #include <basis/except.h> // to throw exceptions
00014 
00015 #include <vector>
00016 #include <stdlib.h>            // malloc(), free()
00017 #include <string.h>            // strncmp()
00018 
00019 #if WINDOWS
00020 #  include <direct.h>          // _getcwd()
00021 #  include <windows.h>         // GetModuleFileName()
00022 #else
00023 #  include <unistd.h>          // getcwd(), rmdir()
00024 #  include <dirent.h>          // opendir()
00025 #  include <sys/stat.h>        // mkdir()
00026 #endif
00027 #if MACOS
00028 #  include <mach-o/dyld.h>     // _NSGetExecutablePath()
00029 #endif
00030 
00031 #include <basis/os.h>
00032 #include <basis/os/path.h>
00033 
00034 
00035 // acceptable in .cxx file
00036 using namespace std;
00037 
00038 
00039 namespace basis { namespace os {
00040 
00041 
00042 // ---------------------------------------------------------------------------
00043 string getcwd()
00044 {
00045     string wd;
00046 #if WINDOWS
00047     char* buffer = _getcwd(NULL, 0);
00048 #else
00049     char* buffer = ::getcwd(NULL, 0);
00050 #endif
00051     if (buffer) {
00052         wd = buffer;
00053         free(buffer);
00054     }
00055     return wd;
00056 }
00057 
00058 // ---------------------------------------------------------------------------
00059 string exepath()
00060 {
00061     string path;
00062 #if LINUX
00063     path = path::realpath("/proc/self/exe");
00064 #elif WINDOWS
00065     LPTSTR buffer = NULL;
00066     LPTSTR newbuf = NULL;
00067     DWORD buflen = 256;
00068     DWORD retval = 0;
00069 
00070     for (;;) {
00071         newbuf = static_cast<LPTSTR>(realloc(buffer, buflen * sizeof(TCHAR)));
00072         if (!newbuf) break;
00073         buffer = newbuf;
00074         retval = GetModuleFileName(NULL, buffer, buflen);
00075         if (retval == 0 || retval < buflen) break;
00076         buflen += 256;
00077         retval = 0;
00078     }
00079 
00080     if (retval > 0) {
00081 #  ifdef UNICODE
00082         int n = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
00083         char* mbpath = static_cast<char*>(malloc(n));
00084         if (mbpath) {
00085             WideCharToMultiByte(CP_UTF8, 0, buffer, -1, mbpath, n, NULL, NULL);
00086             path = mbpath;
00087             free(mbpath);
00088         }
00089 #  else
00090         path = buffer;
00091 #  endif
00092     }
00093 
00094     free (buffer);
00095 #elif MACOS
00096     char* buffer = NULL;
00097     char* newbuf = NULL;
00098     uint32_t buflen = 256;
00099 
00100     buffer = reinterpret_cast<char*>(malloc(buflen * sizeof(char)));
00101     if (buffer) {
00102         if (_NSGetExecutablePath(buffer, &buflen) == 0) {
00103             path = buffer;
00104         } else {
00105             newbuf = reinterpret_cast<char*>(realloc(buffer, buflen * sizeof(char)));
00106             if (newbuf) {
00107                 buffer = newbuf;
00108                 if (_NSGetExecutablePath(buffer, &buflen) == 0) {
00109                     path = buffer;
00110                 }
00111             }
00112         }
00113     }
00114 
00115     free(buffer);
00116 #else
00117     // functionality not supported on this (unknown) platform
00118 #endif
00119     return path::normpath(path);
00120 }
00121 
00122 // ---------------------------------------------------------------------------
00123 string exename()
00124 {
00125     string exec_path = exepath();
00126     if (exec_path.empty()) return "";
00127 #if WINDOWS
00128     string head, ext;
00129     path::splitext(exec_path, head, ext);
00130     if (ext == ".exe" || ext == ".com") exec_path = head;
00131 #endif
00132     return path::basename(exec_path);
00133 }
00134 
00135 // ---------------------------------------------------------------------------
00136 string exedir()
00137 {
00138     string path = exepath();
00139     return path.empty() ? "" : path::dirname(path);
00140 }
00141 
00142 // ---------------------------------------------------------------------------
00143 string readlink(const string& path)
00144 {
00145     string value;
00146 #if UNIX
00147     char* buffer = NULL;
00148     char* newbuf = NULL;
00149     size_t buflen = 256;
00150     for (;;) {
00151         newbuf = reinterpret_cast<char*>(realloc(buffer, buflen * sizeof(char)));
00152         if (!newbuf) break;
00153         buffer = newbuf;
00154         int n = ::readlink(path.c_str(), buffer, buflen);
00155         if (n < 0) break;
00156         if (static_cast<size_t>(n) < buflen) {
00157             buffer[n] = '\0';
00158             value = buffer;
00159             break;
00160         }
00161         buflen += 256;
00162     }
00163     free(buffer);
00164 #endif
00165     return value;
00166 }
00167 
00168 // ---------------------------------------------------------------------------
00169 // common implementation of mkdir() and makedirs()
00170 static inline bool makedir(const string& path, bool parent)
00171 {
00172     if (path.empty()) return true; // cwd already exists
00173     if (path::isfile(path)) return false;
00174     vector<string> dirs;
00175     string         dir(path);
00176     if (parent) {
00177         while (!dir.empty() && !path::exists(dir)) {
00178             dirs.push_back(dir);
00179             dir = path::dirname(dir);
00180         }
00181     } else if (!path::exists(dir)) {
00182         dirs.push_back(dir);
00183     }
00184     for (vector<string>::reverse_iterator it = dirs.rbegin(); it != dirs.rend(); ++it) {
00185 #if WINDOWS
00186         if (CreateDirectory(it->c_str(), NULL) == FALSE) return false;
00187 #else
00188         if (::mkdir(it->c_str(), 0755) != 0) return false;
00189 #endif
00190     }
00191     return true;
00192 }
00193 
00194 // ---------------------------------------------------------------------------
00195 bool mkdir(const string& path)
00196 {
00197     return makedir(path, false);
00198 }
00199 
00200 // ---------------------------------------------------------------------------
00201 bool makedirs(const string& path)
00202 {
00203     return makedir(path, true);
00204 }
00205 
00206 // ---------------------------------------------------------------------------
00207 // common implementation of rmdir() and rmtree()
00208 static inline bool removedir(const string& path, bool recursive)
00209 {
00210     // remove files and subdirectories - recursive implementation
00211     if (recursive && !emptydir(path)) return false;
00212     // remove this directory
00213 #if WINDOWS
00214     return (::SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_NORMAL) == TRUE) &&
00215            (::RemoveDirectory(path.c_str()) == TRUE);
00216 #else
00217     return ::rmdir(path.c_str()) == 0;
00218 #endif
00219 }
00220 
00221 // ---------------------------------------------------------------------------
00222 bool rmdir(const string& path)
00223 {
00224     return removedir(path, false);
00225 }
00226 
00227 // ---------------------------------------------------------------------------
00228 bool rmtree(const string& path)
00229 {
00230     return removedir(path, true);
00231 }
00232 
00233 // ---------------------------------------------------------------------------
00234 bool emptydir(const string& path)
00235 {
00236     bool ok = true;
00237     string subpath; // either subdirectory or file path
00238 
00239 #if WINDOWS
00240     WIN32_FIND_DATA info;
00241     HANDLE hFile = ::FindFirstFile(path::join(path, "*.*").c_str(), &info);
00242     if (hFile != INVALID_HANDLE_VALUE) {
00243         do {
00244             // skip '.' and '..'
00245             if (strncmp(info.cFileName, ".", 2) == 0 || strncmp(info.cFileName, "..", 3) == 0) {
00246                 continue;
00247             }
00248             // remove subdirectory or file, respectively
00249             subpath = path::join(path, info.cFileName);
00250             if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
00251                 if (!removedir(subpath, true)) ok = false;
00252             } else {
00253                 if (::SetFileAttributes(subpath.c_str(), FILE_ATTRIBUTE_NORMAL) == FALSE ||
00254                     ::DeleteFile(subpath.c_str()) == FALSE) ok = false;
00255             }
00256         } while (::FindNextFile(hFile, &info) == TRUE);
00257         ::FindClose(hFile);
00258     }
00259 #else
00260     struct dirent *p = NULL;
00261     DIR *d = opendir(path.c_str());
00262     if (d != NULL) {
00263         while ((p = readdir(d)) != NULL) {
00264             // skip '.' and '..'
00265             if (strncmp(p->d_name, ".", 2) == 0 || strncmp(p->d_name, "..", 3) == 0) {
00266                 continue;
00267             }
00268             // remove subdirectory or file, respectively
00269             subpath = path::join(path, p->d_name);
00270             if (path::isdir(subpath)) {
00271                 if (!rmtree(subpath)) ok = false;
00272             } else {
00273                 if (unlink(subpath.c_str()) != 0) ok = false;
00274             }
00275         }
00276         closedir(d);
00277     }
00278 #endif
00279     return ok;
00280 }
00281 
00282 
00283 } // namespace os
00284 
00285 } // namespace basis