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