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