Blender  V3.3
path.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2011-2022 Blender Foundation */
3 
4 #include "util/path.h"
5 #include "util/md5.h"
6 #include "util/string.h"
7 
8 #include <OpenImageIO/filesystem.h>
9 #include <OpenImageIO/strutil.h>
10 #include <OpenImageIO/sysutil.h>
11 
12 OIIO_NAMESPACE_USING
13 
14 #include <stdio.h>
15 
16 #include <sys/stat.h>
17 
18 #if defined(_WIN32)
19 # define DIR_SEP '\\'
20 # define DIR_SEP_ALT '/'
21 # include <direct.h>
22 #else
23 # define DIR_SEP '/'
24 # include <dirent.h>
25 # include <pwd.h>
26 # include <sys/types.h>
27 # include <unistd.h>
28 #endif
29 
30 #ifdef HAVE_SHLWAPI_H
31 # include <shlwapi.h>
32 #endif
33 
34 #include "util/map.h"
35 #include "util/windows.h"
36 
38 
39 #ifdef _WIN32
40 # if defined(_MSC_VER) || defined(__MINGW64__)
41 typedef struct _stat64 path_stat_t;
42 # elif defined(__MINGW32__)
43 typedef struct _stati64 path_stat_t;
44 # else
45 typedef struct _stat path_stat_t;
46 # endif
47 # ifndef S_ISDIR
48 # define S_ISDIR(x) (((x)&_S_IFDIR) == _S_IFDIR)
49 # endif
50 #else
51 typedef struct stat path_stat_t;
52 #endif
53 
54 static string cached_path = "";
55 static string cached_user_path = "";
56 static string cached_xdg_cache_path = "";
57 
58 namespace {
59 
60 #ifdef _WIN32
61 class directory_iterator {
62  public:
63  class path_info {
64  public:
65  path_info(const string &path, const WIN32_FIND_DATAW &find_data)
66  : path_(path), find_data_(find_data)
67  {
68  }
69 
70  string path()
71  {
72  return path_join(path_, string_from_wstring(find_data_.cFileName));
73  }
74 
75  protected:
76  const string &path_;
77  const WIN32_FIND_DATAW &find_data_;
78  };
79 
80  directory_iterator() : path_info_("", find_data_), h_find_(INVALID_HANDLE_VALUE)
81  {
82  }
83 
84  explicit directory_iterator(const string &path) : path_(path), path_info_(path, find_data_)
85  {
86  string wildcard = path;
87  if (wildcard[wildcard.size() - 1] != DIR_SEP) {
88  wildcard += DIR_SEP;
89  }
90  wildcard += "*";
91  h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(), &find_data_);
92  if (h_find_ != INVALID_HANDLE_VALUE) {
93  skip_dots();
94  }
95  }
96 
97  ~directory_iterator()
98  {
99  if (h_find_ != INVALID_HANDLE_VALUE) {
100  FindClose(h_find_);
101  }
102  }
103 
104  directory_iterator &operator++()
105  {
106  step();
107  return *this;
108  }
109 
110  path_info *operator->()
111  {
112  return &path_info_;
113  }
114 
115  bool operator!=(const directory_iterator &other)
116  {
117  return h_find_ != other.h_find_;
118  }
119 
120  protected:
121  bool step()
122  {
123  if (do_step()) {
124  return skip_dots();
125  }
126  return false;
127  }
128 
129  bool do_step()
130  {
131  if (h_find_ != INVALID_HANDLE_VALUE) {
132  bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
133  if (!result) {
134  FindClose(h_find_);
135  h_find_ = INVALID_HANDLE_VALUE;
136  }
137  return result;
138  }
139  return false;
140  }
141 
142  bool skip_dots()
143  {
144  while (wcscmp(find_data_.cFileName, L".") == 0 || wcscmp(find_data_.cFileName, L"..") == 0) {
145  if (!do_step()) {
146  return false;
147  }
148  }
149  return true;
150  }
151 
152  string path_;
153  path_info path_info_;
154  WIN32_FIND_DATAW find_data_;
155  HANDLE h_find_;
156 };
157 #else /* _WIN32 */
158 
159 class directory_iterator {
160  public:
161  class path_info {
162  public:
163  explicit path_info(const string &path) : path_(path), entry_(NULL)
164  {
165  }
166 
167  string path()
168  {
169  return path_join(path_, entry_->d_name);
170  }
171 
172  void current_entry_set(const struct dirent *entry)
173  {
174  entry_ = entry;
175  }
176 
177  protected:
178  const string &path_;
179  const struct dirent *entry_;
180  };
181 
182  directory_iterator() : path_info_(""), name_list_(NULL), num_entries_(-1), cur_entry_(-1)
183  {
184  }
185 
186  explicit directory_iterator(const string &path) : path_(path), path_info_(path_), cur_entry_(0)
187  {
188  num_entries_ = scandir(path.c_str(), &name_list_, NULL, alphasort);
189  if (num_entries_ < 0) {
190  perror("scandir");
191  }
192  else {
193  skip_dots();
194  }
195  }
196 
197  ~directory_iterator()
198  {
199  destroy_name_list();
200  }
201 
202  directory_iterator &operator++()
203  {
204  step();
205  return *this;
206  }
207 
208  path_info *operator->()
209  {
210  path_info_.current_entry_set(name_list_[cur_entry_]);
211  return &path_info_;
212  }
213 
214  bool operator!=(const directory_iterator &other)
215  {
216  return name_list_ != other.name_list_;
217  }
218 
219  protected:
220  bool step()
221  {
222  if (do_step()) {
223  return skip_dots();
224  }
225  return false;
226  }
227 
228  bool do_step()
229  {
230  ++cur_entry_;
231  if (cur_entry_ >= num_entries_) {
232  destroy_name_list();
233  return false;
234  }
235  return true;
236  }
237 
238  /* Skip . and .. folders. */
239  bool skip_dots()
240  {
241  while (strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
242  strcmp(name_list_[cur_entry_]->d_name, "..") == 0) {
243  if (!step()) {
244  return false;
245  }
246  }
247  return true;
248  }
249 
250  void destroy_name_list()
251  {
252  if (name_list_ == NULL) {
253  return;
254  }
255  for (int i = 0; i < num_entries_; ++i) {
256  free(name_list_[i]);
257  }
258  free(name_list_);
259  name_list_ = NULL;
260  }
261 
262  string path_;
263  path_info path_info_;
264  struct dirent **name_list_;
265  int num_entries_, cur_entry_;
266 };
267 
268 #endif /* _WIN32 */
269 
270 size_t find_last_slash(const string &path)
271 {
272  for (size_t i = 0; i < path.size(); ++i) {
273  size_t index = path.size() - 1 - i;
274 #ifdef _WIN32
275  if (path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
276 #else
277  if (path[index] == DIR_SEP)
278 #endif
279  {
280  return index;
281  }
282  }
283  return string::npos;
284 }
285 
286 } /* namespace */
287 
288 static char *path_specials(const string &sub)
289 {
290  static bool env_init = false;
291  static char *env_shader_path;
292  static char *env_source_path;
293  if (!env_init) {
294  env_shader_path = getenv("CYCLES_SHADER_PATH");
295  /* NOTE: It is KERNEL in env variable for compatibility reasons. */
296  env_source_path = getenv("CYCLES_KERNEL_PATH");
297  env_init = true;
298  }
299  if (env_shader_path != NULL && sub == "shader") {
300  return env_shader_path;
301  }
302  else if (env_source_path != NULL && sub == "source") {
303  return env_source_path;
304  }
305  return NULL;
306 }
307 
308 #if defined(__linux__) || defined(__APPLE__)
309 static string path_xdg_cache_get()
310 {
311  const char *home = getenv("XDG_CACHE_HOME");
312  if (home) {
313  return string(home);
314  }
315  else {
316  home = getenv("HOME");
317  if (home == NULL) {
318  home = getpwuid(getuid())->pw_dir;
319  }
320  return path_join(string(home), ".cache");
321  }
322 }
323 #endif
324 
325 void path_init(const string &path, const string &user_path)
326 {
327  cached_path = path;
328  cached_user_path = user_path;
329 
330 #ifdef _MSC_VER
331  // workaround for https://svn.boost.org/trac/boost/ticket/6320
332  // indirectly init boost codec here since it's not thread safe, and can
333  // cause crashes when it happens in multithreaded image load
334  OIIO::Filesystem::exists(path);
335 #endif
336 }
337 
338 string path_get(const string &sub)
339 {
340  char *special = path_specials(sub);
341  if (special != NULL)
342  return special;
343 
344  if (cached_path == "")
345  cached_path = path_dirname(Sysutil::this_program_path());
346 
347  return path_join(cached_path, sub);
348 }
349 
350 string path_user_get(const string &sub)
351 {
352  if (cached_user_path == "")
353  cached_user_path = path_dirname(Sysutil::this_program_path());
354 
355  return path_join(cached_user_path, sub);
356 }
357 
358 string path_cache_get(const string &sub)
359 {
360 #if defined(__linux__) || defined(__APPLE__)
361  if (cached_xdg_cache_path == "") {
362  cached_xdg_cache_path = path_xdg_cache_get();
363  }
364  string result = path_join(cached_xdg_cache_path, "cycles");
365  return path_join(result, sub);
366 #else
367  /* TODO(sergey): What that should be on Windows? */
368  return path_user_get(path_join("cache", sub));
369 #endif
370 }
371 
372 #if defined(__linux__) || defined(__APPLE__)
373 string path_xdg_home_get(const string &sub = "");
374 #endif
375 
376 string path_filename(const string &path)
377 {
378  size_t index = find_last_slash(path);
379  if (index != string::npos) {
380  /* Corner cases to match boost behavior. */
381 #ifndef _WIN32
382  if (index == 0 && path.size() == 1) {
383  return path;
384  }
385 #endif
386  if (index == path.size() - 1) {
387 #ifdef _WIN32
388  if (index == 2) {
389  return string(1, DIR_SEP);
390  }
391 #endif
392  return ".";
393  }
394  return path.substr(index + 1, path.size() - index - 1);
395  }
396  return path;
397 }
398 
399 string path_dirname(const string &path)
400 {
401  size_t index = find_last_slash(path);
402  if (index != string::npos) {
403 #ifndef _WIN32
404  if (index == 0 && path.size() > 1) {
405  return string(1, DIR_SEP);
406  }
407 #endif
408  return path.substr(0, index);
409  }
410  return "";
411 }
412 
413 string path_join(const string &dir, const string &file)
414 {
415  if (dir.size() == 0) {
416  return file;
417  }
418  if (file.size() == 0) {
419  return dir;
420  }
421  string result = dir;
422 #ifndef _WIN32
423  if (result[result.size() - 1] != DIR_SEP && file[0] != DIR_SEP)
424 #else
425  if (result[result.size() - 1] != DIR_SEP && result[result.size() - 1] != DIR_SEP_ALT &&
426  file[0] != DIR_SEP && file[0] != DIR_SEP_ALT)
427 #endif
428  {
429  result += DIR_SEP;
430  }
431  result += file;
432  return result;
433 }
434 
435 string path_escape(const string &path)
436 {
437  string result = path;
438  string_replace(result, " ", "\\ ");
439  return result;
440 }
441 
442 bool path_is_relative(const string &path)
443 {
444 #ifdef _WIN32
445 # ifdef HAVE_SHLWAPI_H
446  return PathIsRelative(path.c_str());
447 # else /* HAVE_SHLWAPI_H */
448  if (path.size() >= 3) {
449  return !(((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z')) &&
450  path[1] == ':' && path[2] == DIR_SEP);
451  }
452  return true;
453 # endif /* HAVE_SHLWAPI_H */
454 #else /* _WIN32 */
455  if (path.size() == 0) {
456  return 1;
457  }
458  return path[0] != DIR_SEP;
459 #endif /* _WIN32 */
460 }
461 
462 #ifdef _WIN32
463 /* Add a slash if the UNC path points to a share. */
464 static string path_unc_add_slash_to_share(const string &path)
465 {
466  size_t slash_after_server = path.find(DIR_SEP, 2);
467  if (slash_after_server != string::npos) {
468  size_t slash_after_share = path.find(DIR_SEP, slash_after_server + 1);
469  if (slash_after_share == string::npos) {
470  return path + DIR_SEP;
471  }
472  }
473  return path;
474 }
475 
476 /* Convert:
477  * \\?\UNC\server\share\folder\... to \\server\share\folder\...
478  * \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
479  */
480 static string path_unc_to_short(const string &path)
481 {
482  size_t len = path.size();
483  if ((len > 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP) && (path[2] == '?') &&
484  ((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT))) {
485  if ((len > 5) && (path[5] == ':')) {
486  return path.substr(4, len - 4);
487  }
488  else if ((len > 7) && (path.substr(4, 3) == "UNC") &&
489  ((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT))) {
490  return "\\\\" + path.substr(8, len - 8);
491  }
492  }
493  return path;
494 }
495 
496 static string path_cleanup_unc(const string &path)
497 {
498  string result = path_unc_to_short(path);
499  if (path.size() > 2) {
500  /* It's possible path is now a non-UNC. */
501  if (result[0] == DIR_SEP && result[1] == DIR_SEP) {
502  return path_unc_add_slash_to_share(result);
503  }
504  }
505  return result;
506 }
507 
508 /* Make path compatible for stat() functions. */
509 static string path_make_compatible(const string &path)
510 {
511  string result = path;
512  /* In Windows stat() doesn't recognize dir ending on a slash. */
513  if (result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
514  result.resize(result.size() - 1);
515  }
516  /* Clean up UNC path. */
517  if ((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
518  result = path_cleanup_unc(result);
519  }
520  /* Make sure volume-only path ends up wit a directory separator. */
521  if (result.size() == 2 && result[1] == ':') {
522  result += DIR_SEP;
523  }
524  return result;
525 }
526 
527 static int path_wstat(const wstring &path_wc, path_stat_t *st)
528 {
529 # if defined(_MSC_VER) || defined(__MINGW64__)
530  return _wstat64(path_wc.c_str(), st);
531 # elif defined(__MINGW32__)
532  return _wstati64(path_wc.c_str(), st);
533 # else
534  return _wstat(path_wc.c_str(), st);
535 # endif
536 }
537 
538 static int path_stat(const string &path, path_stat_t *st)
539 {
540  wstring path_wc = string_to_wstring(path);
541  return path_wstat(path_wc, st);
542 }
543 #else /* _WIN32 */
544 static int path_stat(const string &path, path_stat_t *st)
545 {
546  return stat(path.c_str(), st);
547 }
548 #endif /* _WIN32 */
549 
550 size_t path_file_size(const string &path)
551 {
552  path_stat_t st;
553  if (path_stat(path, &st) != 0) {
554  return -1;
555  }
556  return st.st_size;
557 }
558 
559 bool path_exists(const string &path)
560 {
561 #ifdef _WIN32
562  string fixed_path = path_make_compatible(path);
563  wstring path_wc = string_to_wstring(fixed_path);
564  path_stat_t st;
565  if (path_wstat(path_wc, &st) != 0) {
566  return false;
567  }
568  return st.st_mode != 0;
569 #else /* _WIN32 */
570  struct stat st;
571  if (stat(path.c_str(), &st) != 0) {
572  return 0;
573  }
574  return st.st_mode != 0;
575 #endif /* _WIN32 */
576 }
577 
578 bool path_is_directory(const string &path)
579 {
580  path_stat_t st;
581  if (path_stat(path, &st) != 0) {
582  return false;
583  }
584  return S_ISDIR(st.st_mode);
585 }
586 
587 static void path_files_md5_hash_recursive(MD5Hash &hash, const string &dir)
588 {
589  if (path_exists(dir)) {
590  directory_iterator it(dir), it_end;
591 
592  for (; it != it_end; ++it) {
593  if (path_is_directory(it->path())) {
594  path_files_md5_hash_recursive(hash, it->path());
595  }
596  else {
597  string filepath = it->path();
598 
599  hash.append((const uint8_t *)filepath.c_str(), filepath.size());
600  hash.append_file(filepath);
601  }
602  }
603  }
604 }
605 
606 string path_files_md5_hash(const string &dir)
607 {
608  /* computes md5 hash of all files in the directory */
609  MD5Hash hash;
610 
612 
613  return hash.get_hex();
614 }
615 
616 static bool create_directories_recursivey(const string &path)
617 {
618  if (path_is_directory(path)) {
619  /* Directory already exists, nothing to do. */
620  return true;
621  }
622  if (path_exists(path)) {
623  /* File exists and it's not a directory. */
624  return false;
625  }
626 
627  string parent = path_dirname(path);
628  if (parent.size() > 0 && parent != path) {
629  if (!create_directories_recursivey(parent)) {
630  return false;
631  }
632  }
633 
634 #ifdef _WIN32
635  wstring path_wc = string_to_wstring(path);
636  return _wmkdir(path_wc.c_str()) == 0;
637 #else
638  return mkdir(path.c_str(), 0777) == 0;
639 #endif
640 }
641 
642 void path_create_directories(const string &filepath)
643 {
644  string path = path_dirname(filepath);
646 }
647 
648 bool path_write_binary(const string &path, const vector<uint8_t> &binary)
649 {
651 
652  /* write binary file from memory */
653  FILE *f = path_fopen(path, "wb");
654 
655  if (!f)
656  return false;
657 
658  if (binary.size() > 0)
659  fwrite(&binary[0], sizeof(uint8_t), binary.size(), f);
660 
661  fclose(f);
662 
663  return true;
664 }
665 
666 bool path_write_text(const string &path, string &text)
667 {
668  vector<uint8_t> binary(text.length(), 0);
669  std::copy(text.begin(), text.end(), binary.begin());
670 
671  return path_write_binary(path, binary);
672 }
673 
674 bool path_read_binary(const string &path, vector<uint8_t> &binary)
675 {
676  /* read binary file into memory */
677  FILE *f = path_fopen(path, "rb");
678 
679  if (!f) {
680  binary.resize(0);
681  return false;
682  }
683 
684  binary.resize(path_file_size(path));
685 
686  if (binary.size() == 0) {
687  fclose(f);
688  return false;
689  }
690 
691  if (fread(&binary[0], sizeof(uint8_t), binary.size(), f) != binary.size()) {
692  fclose(f);
693  return false;
694  }
695 
696  fclose(f);
697 
698  return true;
699 }
700 
701 bool path_read_text(const string &path, string &text)
702 {
703  vector<uint8_t> binary;
704 
705  if (!path_exists(path) || !path_read_binary(path, binary))
706  return false;
707 
708  const char *str = (const char *)&binary[0];
709  size_t size = binary.size();
710  text = string(str, size);
711 
712  return true;
713 }
714 
715 uint64_t path_modified_time(const string &path)
716 {
717  path_stat_t st;
718  if (path_stat(path, &st) != 0) {
719  return 0;
720  }
721  return st.st_mtime;
722 }
723 
724 bool path_remove(const string &path)
725 {
726  return remove(path.c_str()) == 0;
727 }
728 
730  typedef map<string, string> ProcessedMapping;
731  /* Base director for all relative include headers. */
732  string base;
733  /* Result of processed files. */
735  /* Set of files containing #pragma once which have been included. */
736  set<string> pragma_onced;
737 };
738 
739 static string path_source_replace_includes_recursive(const string &source,
740  const string &source_filepath,
742 
743 static string path_source_handle_preprocessor(const string &preprocessor_line,
744  const string &source_filepath,
746 {
747  string result = preprocessor_line;
748 
749  string rest_of_line = string_strip(preprocessor_line.substr(1));
750 
751  if (0 == strncmp(rest_of_line.c_str(), "include", 7)) {
752  rest_of_line = string_strip(rest_of_line.substr(8));
753  if (rest_of_line[0] == '"') {
754  const size_t n_start = 1;
755  const size_t n_end = rest_of_line.find("\"", n_start);
756  const string filename = rest_of_line.substr(n_start, n_end - n_start);
757 
758  string filepath = path_join(state->base, filename);
759  if (!path_exists(filepath)) {
760  filepath = path_join(path_dirname(source_filepath), filename);
761  }
762  string text;
763  if (path_read_text(filepath, text)) {
764  text = path_source_replace_includes_recursive(text, filepath, state);
765  /* Use line directives for better error messages. */
766  return "\n" + text + "\n";
767  }
768  }
769  }
770 
771  return result;
772 }
773 
774 /* Our own little c preprocessor that replaces #includes with the file
775  * contents, to work around issue of OpenCL drivers not supporting
776  * include paths with spaces in them.
777  */
778 static string path_source_replace_includes_recursive(const string &_source,
779  const string &source_filepath,
781 {
782  const string *psource = &_source;
783  string source_new;
784 
785  auto pragma_once = _source.find("#pragma once");
786  if (pragma_once != string::npos) {
787  if (state->pragma_onced.find(source_filepath) != state->pragma_onced.end()) {
788  return "";
789  }
790  state->pragma_onced.insert(source_filepath);
791 
792  // "#pragma once"
793  // "//prgma once"
794  source_new = _source;
795  memcpy(source_new.data() + pragma_once, "//pr", 4);
796  psource = &source_new;
797  }
798 
799  /* Try to re-use processed file without spending time on replacing all
800  * include directives again.
801  */
802  SourceReplaceState::ProcessedMapping::iterator replaced_file = state->processed_files.find(
803  source_filepath);
804  if (replaced_file != state->processed_files.end()) {
805  return replaced_file->second;
806  }
807 
808  const string &source = *psource;
809 
810  /* Perform full file processing. */
811  string result = "";
812  const size_t source_length = source.length();
813  size_t index = 0;
814  /* Information about where we are in the source. */
815  size_t line_number = 0, column_number = 1;
816  /* Currently gathered non-preprocessor token.
817  * Store as start/length rather than token itself to avoid overhead of
818  * memory re-allocations on each character concatenation.
819  */
820  size_t token_start = 0, token_length = 0;
821  /* Denotes whether we're inside of preprocessor line, together with
822  * preprocessor line itself.
823  *
824  * TODO(sergey): Investigate whether using token start/end position
825  * gives measurable speedup.
826  */
827  bool inside_preprocessor = false;
828  string preprocessor_line = "";
829  /* Actual loop over the whole source. */
830  while (index < source_length) {
831  char ch = source[index];
832 
833  if (ch == '\n') {
834  if (inside_preprocessor) {
835  string block = path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
836 
837  if (!block.empty()) {
838  result += block;
839  }
840 
841  /* Start gathering net part of the token. */
842  token_start = index;
843  token_length = 0;
844  inside_preprocessor = false;
845  preprocessor_line = "";
846  }
847  column_number = 0;
848  ++line_number;
849  }
850  else if (ch == '#' && column_number == 1 && !inside_preprocessor) {
851  /* Append all possible non-preprocessor token to the result. */
852  if (token_length != 0) {
853  result.append(source, token_start, token_length);
854  token_start = index;
855  token_length = 0;
856  }
857  inside_preprocessor = true;
858  }
859 
860  if (inside_preprocessor) {
861  preprocessor_line += ch;
862  }
863  else {
864  ++token_length;
865  }
866  ++index;
867  ++column_number;
868  }
869  /* Append possible tokens which happened before special events handled
870  * above.
871  */
872  if (token_length != 0) {
873  result.append(source, token_start, token_length);
874  }
875  if (inside_preprocessor) {
876  result += path_source_handle_preprocessor(preprocessor_line, source_filepath, state);
877  }
878  /* Store result for further reuse. */
879  state->processed_files[source_filepath] = result;
880  return result;
881 }
882 
883 string path_source_replace_includes(const string &source, const string &path)
884 {
886  state.base = path;
887  return path_source_replace_includes_recursive(source, path, &state);
888 }
889 
890 FILE *path_fopen(const string &path, const string &mode)
891 {
892 #ifdef _WIN32
893  wstring path_wc = string_to_wstring(path);
894  wstring mode_wc = string_to_wstring(mode);
895  return _wfopen(path_wc.c_str(), mode_wc.c_str());
896 #else
897  return fopen(path.c_str(), mode.c_str());
898 #endif
899 }
900 
901 void path_cache_clear_except(const string &name, const set<string> &except)
902 {
903  string dir = path_user_get("cache");
904 
905  if (path_exists(dir)) {
906  directory_iterator it(dir), it_end;
907 
908  for (; it != it_end; ++it) {
909  string filename = path_filename(it->path());
910 
911  if (string_startswith(filename, name.c_str()))
912  if (except.find(filename) == except.end())
913  path_remove(it->path());
914  }
915  }
916 }
917 
void BLI_kdtree_nd_() free(KDTree *tree)
Definition: kdtree_impl.h:102
#define S_ISDIR(x)
Definition: BLI_winstuff.h:48
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
Definition: md5.h:20
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
FILE * file
int len
Definition: draw_manager.c:108
#define str(s)
GPUAttachmentType & operator++(GPUAttachmentType &a)
const int state
#define L
bool remove(void *owner, const AttributeIDRef &attribute_id)
constexpr bool operator!=(StringRef a, StringRef b)
static const pxr::TfToken st("st", pxr::TfToken::Immortal)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
#define hash
Definition: noise.c:153
size_t path_file_size(const string &path)
Definition: path.cpp:550
FILE * path_fopen(const string &path, const string &mode)
Definition: path.cpp:890
static string path_source_replace_includes_recursive(const string &source, const string &source_filepath, SourceReplaceState *state)
Definition: path.cpp:778
static string cached_user_path
Definition: path.cpp:55
void path_cache_clear_except(const string &name, const set< string > &except)
Definition: path.cpp:901
string path_user_get(const string &sub)
Definition: path.cpp:350
string path_cache_get(const string &sub)
Definition: path.cpp:358
bool path_is_directory(const string &path)
Definition: path.cpp:578
string path_dirname(const string &path)
Definition: path.cpp:399
string path_source_replace_includes(const string &source, const string &path)
Definition: path.cpp:883
typedefCCL_NAMESPACE_BEGIN struct stat path_stat_t
Definition: path.cpp:51
static int path_stat(const string &path, path_stat_t *st)
Definition: path.cpp:544
string path_get(const string &sub)
Definition: path.cpp:338
string path_files_md5_hash(const string &dir)
Definition: path.cpp:606
bool path_is_relative(const string &path)
Definition: path.cpp:442
uint64_t path_modified_time(const string &path)
Definition: path.cpp:715
string path_join(const string &dir, const string &file)
Definition: path.cpp:413
#define DIR_SEP
Definition: path.cpp:23
bool path_exists(const string &path)
Definition: path.cpp:559
static bool create_directories_recursivey(const string &path)
Definition: path.cpp:616
string path_escape(const string &path)
Definition: path.cpp:435
bool path_write_binary(const string &path, const vector< uint8_t > &binary)
Definition: path.cpp:648
void path_create_directories(const string &filepath)
Definition: path.cpp:642
bool path_write_text(const string &path, string &text)
Definition: path.cpp:666
static void path_files_md5_hash_recursive(MD5Hash &hash, const string &dir)
Definition: path.cpp:587
static string path_source_handle_preprocessor(const string &preprocessor_line, const string &source_filepath, SourceReplaceState *state)
Definition: path.cpp:743
bool path_read_text(const string &path, string &text)
Definition: path.cpp:701
static string cached_xdg_cache_path
Definition: path.cpp:56
string path_filename(const string &path)
Definition: path.cpp:376
static string cached_path
Definition: path.cpp:54
static char * path_specials(const string &sub)
Definition: path.cpp:288
bool path_remove(const string &path)
Definition: path.cpp:724
void path_init(const string &path, const string &user_path)
Definition: path.cpp:325
bool path_read_binary(const string &path, vector< uint8_t > &binary)
Definition: path.cpp:674
unsigned char uint8_t
Definition: stdint.h:78
unsigned __int64 uint64_t
Definition: stdint.h:90
string string_strip(const string &s)
Definition: string.cpp:122
bool string_startswith(const string_view s, const string_view start)
Definition: string.cpp:100
void string_replace(string &haystack, const string &needle, const string &other)
Definition: string.cpp:130
ProcessedMapping processed_files
Definition: path.cpp:734
set< string > pragma_onced
Definition: path.cpp:736
map< string, string > ProcessedMapping
Definition: path.cpp:730
char * d_name
Definition: BLI_winstuff.h:80