os.cxx
Go to the documentation of this file.
1 // ============================================================================
2 // Copyright (c) 2011-2012 University of Pennsylvania
3 // Copyright (c) 2013-2016 Andreas Schuh
4 // All rights reserved.
5 //
6 // See COPYING file for license information or visit
7 // https://cmake-basis.github.io/download.html#license
8 // ============================================================================
9 
10 /**
11  * @file os.cxx
12  * @brief Operating system dependent functions.
13  */
14 
15 
16 #include <basis/config.h> // platform macros - must be first
17 #include <basis/except.h> // to throw exceptions
18 
19 #include <vector>
20 #include <stdlib.h> // malloc(), free()
21 #include <string.h> // strncmp()
22 
23 #if WINDOWS
24 # include <direct.h> // _getcwd()
25 # include <windows.h> // GetModuleFileName()
26 #else
27 # include <unistd.h> // getcwd(), rmdir()
28 # include <dirent.h> // opendir()
29 # include <sys/stat.h> // mkdir()
30 #endif
31 #if MACOS
32 # include <mach-o/dyld.h> // _NSGetExecutablePath()
33 #endif
34 
35 #include <basis/os.h>
36 #include <basis/os/path.h>
37 
38 
39 // acceptable in .cxx file
40 using namespace std;
41 
42 
43 namespace basis { namespace os {
44 
45 
46 // ---------------------------------------------------------------------------
47 string getcwd()
48 {
49  string wd;
50 #if WINDOWS
51  char* buffer = _getcwd(NULL, 0);
52 #else
53  char* buffer = ::getcwd(NULL, 0);
54 #endif
55  if (buffer) {
56  wd = buffer;
57  free(buffer);
58  }
59  return wd;
60 }
61 
62 // ---------------------------------------------------------------------------
63 string exepath()
64 {
65  string path;
66 #if LINUX
67  path = path::realpath("/proc/self/exe");
68 #elif WINDOWS
69  LPTSTR buffer = NULL;
70  LPTSTR newbuf = NULL;
71  DWORD buflen = 256;
72  DWORD retval = 0;
73 
74  for (;;) {
75  newbuf = static_cast<LPTSTR>(realloc(buffer, buflen * sizeof(TCHAR)));
76  if (!newbuf) break;
77  buffer = newbuf;
78  retval = GetModuleFileName(NULL, buffer, buflen);
79  if (retval == 0 || retval < buflen) break;
80  buflen += 256;
81  retval = 0;
82  }
83 
84  if (retval > 0) {
85 # ifdef UNICODE
86  int n = WideCharToMultiByte(CP_UTF8, 0, buffer, -1, NULL, 0, NULL, NULL);
87  char* mbpath = static_cast<char*>(malloc(n));
88  if (mbpath) {
89  WideCharToMultiByte(CP_UTF8, 0, buffer, -1, mbpath, n, NULL, NULL);
90  path = mbpath;
91  free(mbpath);
92  }
93 # else
94  path = buffer;
95 # endif
96  }
97 
98  free (buffer);
99 #elif MACOS
100  char* buffer = NULL;
101  char* newbuf = NULL;
102  uint32_t buflen = 256;
103 
104  buffer = reinterpret_cast<char*>(malloc(buflen * sizeof(char)));
105  if (buffer) {
106  if (_NSGetExecutablePath(buffer, &buflen) == 0) {
107  path = buffer;
108  } else {
109  newbuf = reinterpret_cast<char*>(realloc(buffer, buflen * sizeof(char)));
110  if (newbuf) {
111  buffer = newbuf;
112  if (_NSGetExecutablePath(buffer, &buflen) == 0) {
113  path = buffer;
114  }
115  }
116  }
117  }
118 
119  free(buffer);
120 #else
121  // functionality not supported on this (unknown) platform
122 #endif
123  return path::normpath(path);
124 }
125 
126 // ---------------------------------------------------------------------------
127 string exename()
128 {
129  string exec_path = exepath();
130  if (exec_path.empty()) return "";
131 #if WINDOWS
132  string head, ext;
133  path::splitext(exec_path, head, ext);
134  if (ext == ".exe" || ext == ".com") exec_path = head;
135 #endif
136  return path::basename(exec_path);
137 }
138 
139 // ---------------------------------------------------------------------------
140 string exedir()
141 {
142  string path = exepath();
143  return path.empty() ? "" : path::dirname(path);
144 }
145 
146 // ---------------------------------------------------------------------------
147 string readlink(const string& path)
148 {
149  string value;
150 #if UNIX
151  char* buffer = NULL;
152  char* newbuf = NULL;
153  size_t buflen = 256;
154  for (;;) {
155  newbuf = reinterpret_cast<char*>(realloc(buffer, buflen * sizeof(char)));
156  if (!newbuf) break;
157  buffer = newbuf;
158  int n = ::readlink(path.c_str(), buffer, buflen);
159  if (n < 0) break;
160  if (static_cast<size_t>(n) < buflen) {
161  buffer[n] = '\0';
162  value = buffer;
163  break;
164  }
165  buflen += 256;
166  }
167  free(buffer);
168 #endif
169  return value;
170 }
171 
172 // ---------------------------------------------------------------------------
173 // common implementation of mkdir() and makedirs()
174 static inline bool makedir(const string& path, bool parent)
175 {
176  if (path.empty()) return true; // cwd already exists
177  if (path::isfile(path)) return false;
178  vector<string> dirs;
179  string dir(path);
180  if (parent) {
181  while (!dir.empty() && !path::exists(dir)) {
182  dirs.push_back(dir);
183  dir = path::dirname(dir);
184  }
185  } else if (!path::exists(dir)) {
186  dirs.push_back(dir);
187  }
188  for (vector<string>::reverse_iterator it = dirs.rbegin(); it != dirs.rend(); ++it) {
189 #if WINDOWS
190  if (CreateDirectory(it->c_str(), NULL) == FALSE) return false;
191 #else
192  if (::mkdir(it->c_str(), 0755) != 0) return false;
193 #endif
194  }
195  return true;
196 }
197 
198 // ---------------------------------------------------------------------------
199 bool mkdir(const string& path)
200 {
201  return makedir(path, false);
202 }
203 
204 // ---------------------------------------------------------------------------
205 bool makedirs(const string& path)
206 {
207  return makedir(path, true);
208 }
209 
210 // ---------------------------------------------------------------------------
211 // common implementation of rmdir() and rmtree()
212 static inline bool removedir(const string& path, bool recursive)
213 {
214  // remove files and subdirectories - recursive implementation
215  if (recursive && !emptydir(path)) return false;
216  // remove this directory
217 #if WINDOWS
218  return (::SetFileAttributes(path.c_str(), FILE_ATTRIBUTE_NORMAL) == TRUE) &&
219  (::RemoveDirectory(path.c_str()) == TRUE);
220 #else
221  return ::rmdir(path.c_str()) == 0;
222 #endif
223 }
224 
225 // ---------------------------------------------------------------------------
226 bool rmdir(const string& path)
227 {
228  return removedir(path, false);
229 }
230 
231 // ---------------------------------------------------------------------------
232 bool rmtree(const string& path)
233 {
234  return removedir(path, true);
235 }
236 
237 // ---------------------------------------------------------------------------
238 bool emptydir(const string& path)
239 {
240  bool ok = true;
241  string subpath; // either subdirectory or file path
242 
243 #if WINDOWS
244  WIN32_FIND_DATA info;
245  HANDLE hFile = ::FindFirstFile(path::join(path, "*.*").c_str(), &info);
246  if (hFile != INVALID_HANDLE_VALUE) {
247  do {
248  // skip '.' and '..'
249  if (strncmp(info.cFileName, ".", 2) == 0 || strncmp(info.cFileName, "..", 3) == 0) {
250  continue;
251  }
252  // remove subdirectory or file, respectively
253  subpath = path::join(path, info.cFileName);
254  if(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
255  if (!removedir(subpath, true)) ok = false;
256  } else {
257  if (::SetFileAttributes(subpath.c_str(), FILE_ATTRIBUTE_NORMAL) == FALSE ||
258  ::DeleteFile(subpath.c_str()) == FALSE) ok = false;
259  }
260  } while (::FindNextFile(hFile, &info) == TRUE);
261  ::FindClose(hFile);
262  }
263 #else
264  struct dirent *p = NULL;
265  DIR *d = opendir(path.c_str());
266  if (d != NULL) {
267  while ((p = readdir(d)) != NULL) {
268  // skip '.' and '..'
269  if (strncmp(p->d_name, ".", 2) == 0 || strncmp(p->d_name, "..", 3) == 0) {
270  continue;
271  }
272  // remove subdirectory or file, respectively
273  subpath = path::join(path, p->d_name);
274  if (path::isdir(subpath)) {
275  if (!rmtree(subpath)) ok = false;
276  } else {
277  if (unlink(subpath.c_str()) != 0) ok = false;
278  }
279  }
280  closedir(d);
281  }
282 #endif
283  return ok;
284 }
285 
286 
287 } // namespace os
288 
289 } // namespace basis
bool mkdir(const std::string &path)
Make directory.
Definition: os.cxx:199
Basic exceptions and related helper macros.
std::string getcwd()
Get absolute path of the (current) working directory.
Definition: os.cxx:47
function normpath(in path)
Clean path, i.e., remove occurences of "./", duplicate slashes,...
function realpath(in path)
Get canonical file path.
function ok(in expression, in name)
Evaluate test expression and fail if it does not evaluate to 0 or check return value of function...
std::string join(const std::string &base, const std::string &path)
Join two paths, e.g., base path and relative path.
Definition: path.cxx:432
System related macro definitions.
STL namespace.
bool rmdir(const std::string &path)
Remove empty directory.
Definition: os.cxx:226
bool emptydir(const std::string &path)
Remove files and directories from directory.
Definition: os.cxx:238
Definition: basis.h:34
bool exists(const std::string path)
Test the existance of a file or directory.
Definition: path.cxx:476
bool isfile(const std::string path)
Test whether a given path is the path of an existent file.
Definition: path.cxx:448
std::string basename(const std::string &path)
Get file name.
Definition: path.cxx:273
bool makedirs(const std::string &path)
Make directory including parent directories if required.
Definition: os.cxx:205
bool rmtree(const std::string &path)
Remove whole directory tree.
Definition: os.cxx:232
function exepath(out path, in target)
Get absolute path of executable file.
Operating system dependent functions.
void splitext(const std::string &path, std::string &head, std::string &ext, const std::set< std::string > *exts=NULL, bool icase=false)
Get file name extension.
Definition: path.cxx:212
std::string dirname(const std::string &path)
Get file directory.
Definition: path.cxx:265
File/directory path related functions.
std::string readlink(const std::string &path)
Read value of symbolic link.
Definition: os.cxx:147
bool isdir(const std::string path)
Test whether a given path is the path of an existent directory.
Definition: path.cxx:462
function exedir(out dir, in name)
Get directory of executable file.
cmake DIR
function exename(out file, in name)
Get name of executable file.