COPASI API  4.16.103
CDirEntry.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 // Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
7 // Properties, Inc., EML Research, gGmbH, University of Heidelberg,
8 // and The University of Manchester.
9 // All rights reserved.
10 
11 // Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual
12 // Properties, Inc. and EML Research, gGmbH.
13 // All rights reserved.
14 
15 #include <algorithm>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 
19 #ifdef WIN32
20 # include <io.h>
21 # include <direct.h>
22 typedef struct _stat STAT;
23 # define stat _wstat
24 # define S_IFREG _S_IFREG
25 # define S_IFDIR _S_IFDIR
26 # define access _waccess
27 # define rename _wrename
28 # define mkdir _wmkdir
29 # define rmdir _wrmdir
30 #else
31 typedef struct stat STAT;
32 # include <dirent.h>
33 # include <unistd.h>
34 #endif // WIN32
35 
36 #include "copasi.h"
37 
38 #include "CDirEntry.h"
39 #include "utility.h"
40 #include "CCopasiMessage.h"
41 
44 
45 #ifdef WIN32
46 # include "commandline/COptions.h"
47 const std::string CDirEntry::Separator = "\\";
48 #else
49 const std::string CDirEntry::Separator = "/";
50 #endif
51 
52 bool CDirEntry::isFile(const std::string & path)
53 {
54  STAT st;
55 
56  if (stat(CLocaleString::fromUtf8(path).c_str(), & st) == -1) return false;
57 
58 #ifdef WIN32
59  return ((st.st_mode & S_IFREG) == S_IFREG);
60 #else
61  return S_ISREG(st.st_mode);
62 #endif
63 }
64 
65 bool CDirEntry::isDir(const std::string & path)
66 {
67  STAT st;
68 
69  if (stat(CLocaleString::fromUtf8(path).c_str(), & st) == -1) return false;
70 
71 #ifdef WIN32
72  return ((st.st_mode & S_IFDIR) == S_IFDIR);
73 #else
74  return S_ISDIR(st.st_mode);
75 #endif
76 }
77 
78 bool CDirEntry::exist(const std::string & path)
79 {
80  STAT st;
81 
82  if (stat(CLocaleString::fromUtf8(path).c_str(), & st) == -1) return false;
83 
84 #ifdef WIN32
85  return ((st.st_mode & S_IFREG) == S_IFREG ||
86  (st.st_mode & S_IFDIR) == S_IFDIR);
87 #else
88  return (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode));
89 #endif
90 }
91 
92 bool CDirEntry::isReadable(const std::string & path)
93 {return (access(CLocaleString::fromUtf8(path).c_str(), 0x4) == 0);}
94 
95 bool CDirEntry::isWritable(const std::string & path)
96 {return (access(CLocaleString::fromUtf8(path).c_str(), 0x2) == 0);}
97 
98 std::string CDirEntry::baseName(const std::string & path)
99 {
100  std::string::size_type start = path.find_last_of(Separator);
101 #ifdef WIN32 // WIN32 also understands '/' as the separator.
102 
103  if (start == std::string::npos)
104  start = path.find_last_of("/");
105 
106 #endif
107 
108  if (start == std::string::npos) start = 0;
109  else start++; // We do not want the separator.
110 
111  std::string::size_type end = path.find_last_of(".");
112 
113  if (end == std::string::npos || end < start)
114  end = path.length();
115 
116  return path.substr(start, end - start);
117 }
118 
119 std::string CDirEntry::fileName(const std::string & path)
120 {
121  std::string::size_type start = path.find_last_of(Separator);
122 #ifdef WIN32 // WIN32 also understands '/' as the separator.
123 
124  if (start == std::string::npos)
125  start = path.find_last_of("/");
126 
127 #endif
128 
129  if (start == std::string::npos) start = 0;
130  else start++; // We do not want the separator.
131 
132  return path.substr(start);
133 }
134 
135 std::string CDirEntry::dirName(const std::string & path)
136 {
137  if (path == "") return path;
138 
139 #ifdef WIN32 // WIN32 also understands '/' as the separator.
140  std::string::size_type end = path.find_last_of(Separator + "/");
141 #else
142  std::string::size_type end = path.find_last_of(Separator);
143 #endif
144 
145  if (end == path.length() - 1)
146  {
147 #ifdef WIN32 // WIN32 also understands '/' as the separator.
148  end = path.find_last_of(Separator + "/", end);
149 #else
150  end = path.find_last_of(Separator, end);
151 #endif
152  }
153 
154  if (end == std::string::npos) return "";
155 
156  return path.substr(0, end);
157 }
158 
159 std::string CDirEntry::suffix(const std::string & path)
160 {
161  std::string::size_type start = path.find_last_of(Separator);
162 #ifdef WIN32 // WIN32 also understands '/' as the separator.
163 
164  if (start == std::string::npos)
165  start = path.find_last_of("/");
166 
167 #endif
168 
169  if (start == std::string::npos) start = 0;
170  else start++; // We do not want the separator.
171 
172  std::string::size_type end = path.find_last_of(".");
173 
174  if (end == std::string::npos || end < start)
175  return "";
176  else
177  return path.substr(end);
178 }
179 
180 bool CDirEntry::createDir(const std::string & dir,
181  const std::string & parent)
182 {
183  std::string Dir;
184 
185  if (parent != "") Dir = parent + Separator;
186 
187  Dir += dir;
188 
189  // Check whether the directory already exists and is writable.
190  if (isDir(Dir) && isWritable(Dir)) return true;
191 
192  // Check whether the parent directory exists and is writable.
193  if (!isDir(parent) || !isWritable(parent)) return false;
194 
195 #ifdef WIN32
196  return (mkdir(CLocaleString::fromUtf8(Dir).c_str()) == 0);
197 #else
198  return (mkdir(CLocaleString::fromUtf8(Dir).c_str(), S_IRWXU | S_IRWXG | S_IRWXO) == 0);
199 #endif
200 }
201 
202 std::string CDirEntry::createTmpName(const std::string & dir,
203  const std::string & suffix)
204 {
205  CRandom * pRandom = CRandom::createGenerator();
206 
207  std::string RandomName;
208 
209  do
210  {
211  RandomName = dir + Separator;
212  unsigned C_INT32 Char;
213 
214  for (size_t i = 0; i < 8; i++)
215  {
216  Char = pRandom->getRandomU(35);
217 
218  if (Char < 10)
219  RandomName += '0' + Char;
220  else
221  RandomName += 'a' - 10 + Char;
222  }
223 
224  RandomName += suffix;
225  }
226  while (exist(RandomName));
227 
228  pdelete(pRandom);
229 
230  return RandomName;
231 }
232 
233 bool CDirEntry::move(const std::string & from,
234  const std::string & to)
235 {
236  if (!isFile(from)) return false;
237 
238  std::string To = to;
239 
240  // Check whether To is a directory and append the
241  // filename of from
242  if (isDir(To))
243  To += Separator + fileName(from);
244 
245  if (isDir(To)) return false;
246 
247 #ifdef WIN32
248 
249  // The target must not exist under WIN32 for rename to succeed.
250  if (exist(To) && !remove(To))
251  return false;
252 
253 #endif // WIN32
254 
255  bool success =
256  (rename(CLocaleString::fromUtf8(from).c_str(), CLocaleString::fromUtf8(To).c_str()) == 0);
257 
258  if (!success)
259  {
260  {
261  std::ifstream in(CLocaleString::fromUtf8(from).c_str());
262  std::ofstream out(CLocaleString::fromUtf8(To).c_str());
263 
264  out << in.rdbuf();
265 
266  success = out.good();
267  }
268 
269  remove(from);
270  }
271 
272  return success;
273 }
274 
275 bool CDirEntry::remove(const std::string & path)
276 {
277  if (isDir(path))
278  return (rmdir(CLocaleString::fromUtf8(path).c_str()) == 0);
279  else if (isFile(path))
280 #ifdef WIN32
281  return (_wremove(CLocaleString::fromUtf8(path).c_str()) == 0);
282 
283 #else
284  return (::remove(CLocaleString::fromUtf8(path).c_str()) == 0);
285 #endif
286 
287  return false;
288 }
289 
290 bool CDirEntry::removeFiles(const std::string & pattern,
291  const std::string & path)
292 {
293  bool success = true;
294  std::vector< std::string > PatternList;
295 
296  PatternList = compilePattern(pattern);
297 
298 #ifdef WIN32
299 
300  // We want the same pattern matching behaviour for all platforms.
301  // Therefore, we do not use the MS provided one and list all files instead.
302  std::string FilePattern = path + "\\*";
303 
304  // Open directory stream and try read info about first entry
305  struct _wfinddata_t Entry;
306  intptr_t hList = _wfindfirst(CLocaleString::fromUtf8(FilePattern).c_str(), &Entry);
307 
308  if (hList == -1) return success;
309 
310  do
311  {
312  std::string Utf8 = CLocaleString(Entry.name).toUtf8();
313 
314  if (match(Utf8, PatternList))
315  {
316  if (Entry.attrib | _A_NORMAL)
317  {
318 #ifdef WIN32
319 
320  if (_wremove(CLocaleString::fromUtf8(path + Separator + Utf8).c_str()) != 0) success = false;
321 
322 #else
323 
324  if (::remove(CLocaleString::fromUtf8(path + Separator + Utf8).c_str()) != 0) success = false;
325 
326 #endif
327  }
328  else
329  {
330  if (rmdir(CLocaleString::fromUtf8(path + Separator + Utf8).c_str()) != 0) success = false;
331  }
332  }
333  }
334  while (_wfindnext(hList, &Entry) == 0);
335 
336  _findclose(hList);
337 
338 #else
339 
340  DIR * pDir = opendir(CLocaleString::fromUtf8(path).c_str());
341 
342  if (!pDir) return false;
343 
344  struct dirent * pEntry;
345 
346  while ((pEntry = readdir(pDir)) != NULL)
347  {
348  std::string Utf8 = CLocaleString(pEntry->d_name).toUtf8();
349 
350  if (match(Utf8, PatternList))
351  {
352  if (isDir(Utf8))
353  {
354  if (rmdir(CLocaleString::fromUtf8(path + Separator + Utf8).c_str()) != 0)
355  success = false;
356  }
357  else
358  {
359  if (::remove(CLocaleString::fromUtf8(path + Separator + Utf8).c_str()) != 0)
360  success = false;
361  }
362  }
363  }
364 
365  closedir(pDir);
366 
367 #endif // WIN32
368 
369  return success;
370 }
371 
372 std::vector< std::string > CDirEntry::compilePattern(const std::string & pattern)
373 {
374  std::string::size_type pos = 0;
375  std::string::size_type start = 0;
376  std::string::size_type end = 0;
377  std::vector< std::string > PatternList;
378 
379  while (pos != std::string::npos)
380  {
381  start = pos;
382  pos = pattern.find_first_of("*?", pos);
383 
384  end = std::min(pos, pattern.length());
385 
386  if (start != end)
387  PatternList.push_back(pattern.substr(start, end - start));
388  else
389  {
390  PatternList.push_back(pattern.substr(start, 1));
391  pos++;
392  }
393  };
394 
395  return PatternList;
396 }
397 
398 bool CDirEntry::match(const std::string & name,
399  const std::vector< std::string > & patternList)
400 {
401  std::vector< std::string >::const_iterator it = patternList.begin();
402  std::vector< std::string >::const_iterator end = patternList.end();
403  std::string::size_type at = 0;
404  std::string::size_type after = 0;
405 
406  bool Match = true;
407 
408  while (it != end && Match)
409  Match = matchInternal(name, *it++, at, after);
410 
411  return Match;
412 }
413 
414 bool CDirEntry::isRelativePath(const std::string & path)
415 {
416 #ifdef WIN32
417  std::string Path = normalize(path);
418 
419  if (Path.length() < 2)
420  return true;
421 
422  if (Path[1] == ':')
423  return false;
424 
425  if (Path[0] == '/' && Path[1] == '/')
426  return false;
427 
428  return true;
429 #else
430  return (path.length() < 1 || path[0] != '/');
431 #endif
432 }
433 
434 bool CDirEntry::makePathRelative(std::string & absolutePath,
435  const std::string & relativeTo)
436 {
437  if (isRelativePath(absolutePath) ||
438  isRelativePath(relativeTo)) return false; // Nothing can be done.
439 
440  std:: string RelativeTo = normalize(relativeTo);
441 
442  if (isFile(RelativeTo)) RelativeTo = dirName(RelativeTo);
443 
444  if (!isDir(RelativeTo)) return false;
445 
446  absolutePath = normalize(absolutePath);
447 
448  size_t i, imax = std::min(absolutePath.length(), RelativeTo.length());
449 
450  for (i = 0; i < imax; i++)
451  if (absolutePath[i] != RelativeTo[i]) break;
452 
453  // We need to retract to the beginning of the current directory.
454  if (i != imax)
455  i = absolutePath.find_last_of('/', i) + 1;
456 
457 #ifdef WIN32
458 
459  if (i == 0) return false; // A different drive letter we cannot do anything
460 
461 #endif
462 
463  RelativeTo = RelativeTo.substr(i);
464 
465  std::string relativePath;
466 
467  while (RelativeTo != "")
468  {
469  relativePath += "../";
470  RelativeTo = dirName(RelativeTo);
471  }
472 
473  if (relativePath != "")
474  absolutePath = relativePath + absolutePath.substr(i);
475  else
476  absolutePath = absolutePath.substr(i + 1);
477 
478  return true;
479 }
480 
481 bool CDirEntry::makePathAbsolute(std::string & relativePath,
482  const std::string & absoluteTo)
483 {
484  if (!isRelativePath(relativePath) ||
485  isRelativePath(absoluteTo)) return false; // Nothing can be done.
486 
487  std:: string AbsoluteTo = normalize(absoluteTo);
488 
489  if (isFile(AbsoluteTo)) AbsoluteTo = dirName(AbsoluteTo);
490 
491  if (!isDir(AbsoluteTo)) return false;
492 
493  relativePath = normalize(relativePath);
494 
495  while (!relativePath.compare(0, 3, "../"))
496  {
497  AbsoluteTo = dirName(AbsoluteTo);
498  relativePath = relativePath.substr(3);
499  }
500 
501  relativePath = AbsoluteTo + "/" + relativePath;
502 
503  return true;
504 }
505 
506 bool CDirEntry::matchInternal(const std::string & name,
507  const std::string pattern,
508  std::string::size_type & at,
509  std::string::size_type & after)
510 {
511  bool Match = true;
512 
513  switch (pattern[0])
514  {
515  case '*':
516 
517  if (at != std::string::npos)
518  {
519  after = at;
520  at = std::string::npos;
521  }
522 
523  break;
524 
525  case '?':
526 
527  if (at != std::string::npos)
528  {
529  ++at;
530  Match = (name.length() >= at);
531  }
532  else
533  {
534  ++after;
535  Match = (name.length() >= after);
536  }
537 
538  break;
539 
540  default:
541 
542  if (at != std::string::npos)
543  {
544  Match = (name.compare(at, pattern.length(), pattern) == 0);
545  at += pattern.length();
546  }
547  else
548  {
549  at = name.find(pattern, after);
550  Match = (at != std::string::npos);
551  at += pattern.length();
552  }
553 
554  break;
555  }
556 
557  return Match;
558 }
559 
560 std::string CDirEntry::normalize(const std::string & path)
561 {
562  std::string Normalized = path;
563 
564 #ifdef WIN32
565  // converts all '\' to '/' (only on WIN32)
566  size_t i, imax;
567 
568  for (i = 0, imax = Normalized.length(); i < imax; i++)
569  if (Normalized[i] == '\\') Normalized[i] = '/';
570 
571  // if the path starts with /[^/] we prepend the current drive letter
572  if (Normalized.length() > 0 && Normalized[0] == '/')
573  {
574  if ((Normalized.length() > 1 && Normalized[1] != '/') ||
575  Normalized.length() == 1)
576  {
577  std::string PWD;
578  COptions::getValue("PWD", PWD);
579 
580  Normalized = PWD.substr(0, 2) + Normalized;
581  }
582  }
583 
584 #endif
585 
586  // Remove leading './'
587  while (!Normalized.compare(0, 2, "./"))
588  Normalized = Normalized.substr(2);
589 
590  // Collapse '//' to '/'
591  std::string::size_type pos = 1;
592 
593  while (true)
594  {
595  pos = Normalized.find("//", pos);
596 
597  if (pos == std::string::npos) break;
598 
599  Normalized.erase(pos, 1);
600  }
601 
602  // Collapse '/./' to '/'
603  pos = 0;
604 
605  while (true)
606  {
607  pos = Normalized.find("/./", pos);
608 
609  if (pos == std::string::npos) break;
610 
611  Normalized.erase(pos, 2);
612  }
613 
614  // Collapse '[^/]+/../' to '/'
615  std::string::size_type start = Normalized.length();
616 
617  while (true)
618  {
619  pos = Normalized.rfind("/../", start);
620 
621  if (pos == std::string::npos) break;
622 
623  start = Normalized.rfind('/', pos - 1);
624 
625  if (start == std::string::npos) break;
626 
627  if (!Normalized.compare(start, 4, "/../")) continue;
628 
629  Normalized.erase(start, pos - start + 3);
630  start = Normalized.length();
631  }
632 
633  return Normalized;
634 }
static bool isFile(const std::string &path)
Definition: CDirEntry.cpp:52
static bool remove(const std::string &path)
Definition: CDirEntry.cpp:275
#define pdelete(p)
Definition: copasi.h:215
static bool isDir(const std::string &path)
Definition: CDirEntry.cpp:65
static bool move(const std::string &from, const std::string &to)
Definition: CDirEntry.cpp:233
static bool isRelativePath(const std::string &path)
Definition: CDirEntry.cpp:414
static bool match(const std::string &name, const std::vector< std::string > &patternList)
Definition: CDirEntry.cpp:398
static std::string fileName(const std::string &path)
Definition: CDirEntry.cpp:119
static bool removeFiles(const std::string &pattern, const std::string &dir)
Definition: CDirEntry.cpp:290
#define C_INT32
Definition: copasi.h:90
static std::string baseName(const std::string &path)
Definition: CDirEntry.cpp:98
static bool matchInternal(const std::string &name, const std::string pattern, std::string::size_type &at, std::string::size_type &after)
Definition: CDirEntry.cpp:506
static std::string dirName(const std::string &path)
Definition: CDirEntry.cpp:135
static CRandom * createGenerator(CRandom::Type type=CRandom::mt19937, unsigned C_INT32 seed=0)
Definition: CRandom.cpp:49
virtual unsigned C_INT32 getRandomU()
Definition: CRandom.cpp:173
static bool createDir(const std::string &dir, const std::string &parent="")
Definition: CDirEntry.cpp:180
static bool exist(const std::string &path)
Definition: CDirEntry.cpp:78
static const std::string Separator
Definition: CDirEntry.h:34
static bool isWritable(const std::string &path)
Definition: CDirEntry.cpp:95
static std::string createTmpName(const std::string &dir, const std::string &suffix)
Definition: CDirEntry.cpp:202
static void getValue(const std::string &name, CType &value)
Definition: COptions.h:124
static std::vector< std::string > compilePattern(const std::string &pattern)
Definition: CDirEntry.cpp:372
std::string toUtf8() const
static std::string normalize(const std::string &path)
Definition: CDirEntry.cpp:560
static bool isReadable(const std::string &path)
Definition: CDirEntry.cpp:92
static CLocaleString fromUtf8(const std::string &utf8)
static bool makePathAbsolute(std::string &relativePath, const std::string &absoluteTo)
Definition: CDirEntry.cpp:481
static bool makePathRelative(std::string &absolutePath, const std::string &relativeTo)
Definition: CDirEntry.cpp:434
static std::string suffix(const std::string &path)
Definition: CDirEntry.cpp:159
#define min(a, b)
Definition: f2c.h:175
struct stat STAT
Definition: CDirEntry.cpp:31