2011-04-27 11:58:34 +00:00
|
|
|
/*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Copyright 2011-2013 Blender Foundation
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
* You may obtain a copy of the License at
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
2011-04-27 11:58:34 +00:00
|
|
|
*
|
2013-08-18 14:16:15 +00:00
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
* See the License for the specific language governing permissions and
|
2014-12-25 01:50:24 +00:00
|
|
|
* limitations under the License.
|
2011-04-27 11:58:34 +00:00
|
|
|
*/
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "util/util_debug.h"
|
|
|
|
#include "util/util_md5.h"
|
|
|
|
#include "util/util_path.h"
|
|
|
|
#include "util/util_string.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-04-01 18:37:24 +00:00
|
|
|
#include <OpenImageIO/filesystem.h>
|
2014-01-10 23:47:58 +00:00
|
|
|
#include <OpenImageIO/strutil.h>
|
2011-04-27 11:58:34 +00:00
|
|
|
#include <OpenImageIO/sysutil.h>
|
2016-02-05 08:09:39 +00:00
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
OIIO_NAMESPACE_USING
|
|
|
|
|
2011-09-09 12:04:39 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#if defined(_WIN32)
|
|
|
|
# define DIR_SEP '\\'
|
|
|
|
# define DIR_SEP_ALT '/'
|
|
|
|
# include <direct.h>
|
|
|
|
#else
|
|
|
|
# define DIR_SEP '/'
|
|
|
|
# include <dirent.h>
|
2016-09-05 14:41:08 +00:00
|
|
|
# include <pwd.h>
|
2016-09-12 14:06:50 +00:00
|
|
|
# include <unistd.h>
|
|
|
|
# include <sys/types.h>
|
2016-02-05 08:09:39 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_SHLWAPI_H
|
|
|
|
# include <shlwapi.h>
|
|
|
|
#endif
|
|
|
|
|
Cycles: Make all #include statements relative to cycles source directory
The idea is to make include statements more explicit and obvious where the
file is coming from, additionally reducing chance of wrong header being
picked up.
For example, it was not obvious whether bvh.h was refferring to builder
or traversal, whenter node.h is a generic graph node or a shader node
and cases like that.
Surely this might look obvious for the active developers, but after some
time of not touching the code it becomes less obvious where file is coming
from.
This was briefly mentioned in T50824 and seems @brecht is fine with such
explicitness, but need to agree with all active developers before committing
this.
Please note that this patch is lacking changes related on GPU/OpenCL
support. This will be solved if/when we all agree this is a good idea to move
forward.
Reviewers: brecht, lukasstockner97, maiself, nirved, dingto, juicyfruit, swerner
Reviewed By: lukasstockner97, maiself, nirved, dingto
Subscribers: brecht
Differential Revision: https://developer.blender.org/D2586
2017-03-28 18:39:14 +00:00
|
|
|
#include "util/util_windows.h"
|
2011-04-27 11:58:34 +00:00
|
|
|
|
|
|
|
CCL_NAMESPACE_BEGIN
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
# if defined(_MSC_VER) || defined(__MINGW64__)
|
|
|
|
typedef struct _stat64 path_stat_t;
|
|
|
|
# elif defined(__MINGW32__)
|
|
|
|
typedef struct _stati64 path_stat_t;
|
|
|
|
# else
|
|
|
|
typedef struct _stat path_stat_t;
|
|
|
|
# endif
|
|
|
|
# ifndef S_ISDIR
|
|
|
|
# define S_ISDIR(x) (((x) & _S_IFDIR) == _S_IFDIR)
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
typedef struct stat path_stat_t;
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
static string cached_path = "";
|
2011-09-09 12:04:39 +00:00
|
|
|
static string cached_user_path = "";
|
2016-09-05 14:41:08 +00:00
|
|
|
static string cached_xdg_cache_path = "";
|
2011-04-27 11:58:34 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
namespace {
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
class directory_iterator {
|
|
|
|
public:
|
|
|
|
class path_info {
|
|
|
|
public:
|
|
|
|
path_info(const string& path,
|
|
|
|
const WIN32_FIND_DATAW& find_data)
|
|
|
|
: path_(path),
|
|
|
|
find_data_(find_data)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
string path() {
|
|
|
|
return path_join(path_, string_from_wstring(find_data_.cFileName));
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
const string& path_;
|
|
|
|
const WIN32_FIND_DATAW& find_data_;
|
|
|
|
};
|
|
|
|
|
|
|
|
directory_iterator()
|
|
|
|
: path_info_("", find_data_),
|
|
|
|
h_find_(INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-11 14:50:10 +00:00
|
|
|
explicit directory_iterator(const string& path)
|
2016-02-05 08:09:39 +00:00
|
|
|
: path_(path),
|
|
|
|
path_info_(path, find_data_)
|
|
|
|
{
|
|
|
|
string wildcard = path;
|
|
|
|
if(wildcard[wildcard.size() - 1] != DIR_SEP) {
|
|
|
|
wildcard += DIR_SEP;
|
|
|
|
}
|
|
|
|
wildcard += "*";
|
|
|
|
h_find_ = FindFirstFileW(string_to_wstring(wildcard).c_str(),
|
|
|
|
&find_data_);
|
|
|
|
if(h_find_ != INVALID_HANDLE_VALUE) {
|
|
|
|
skip_dots();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~directory_iterator()
|
|
|
|
{
|
|
|
|
if(h_find_ != INVALID_HANDLE_VALUE) {
|
|
|
|
FindClose(h_find_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
directory_iterator& operator++()
|
|
|
|
{
|
|
|
|
step();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
path_info* operator-> ()
|
|
|
|
{
|
|
|
|
return &path_info_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const directory_iterator& other)
|
|
|
|
{
|
|
|
|
return h_find_ != other.h_find_;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool step()
|
|
|
|
{
|
|
|
|
if(do_step()) {
|
|
|
|
return skip_dots();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool do_step()
|
|
|
|
{
|
|
|
|
if(h_find_ != INVALID_HANDLE_VALUE) {
|
|
|
|
bool result = FindNextFileW(h_find_, &find_data_) == TRUE;
|
|
|
|
if(!result) {
|
|
|
|
FindClose(h_find_);
|
|
|
|
h_find_ = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool skip_dots()
|
|
|
|
{
|
|
|
|
while(wcscmp(find_data_.cFileName, L".") == 0 ||
|
|
|
|
wcscmp(find_data_.cFileName, L"..") == 0)
|
|
|
|
{
|
|
|
|
if(!do_step()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
string path_;
|
|
|
|
path_info path_info_;
|
|
|
|
WIN32_FIND_DATAW find_data_;
|
|
|
|
HANDLE h_find_;
|
|
|
|
};
|
|
|
|
#else /* _WIN32 */
|
|
|
|
|
|
|
|
class directory_iterator {
|
|
|
|
public:
|
|
|
|
class path_info {
|
|
|
|
public:
|
2016-05-11 14:50:10 +00:00
|
|
|
explicit path_info(const string& path)
|
2016-02-16 14:32:26 +00:00
|
|
|
: path_(path),
|
|
|
|
entry_(NULL)
|
2016-02-05 08:09:39 +00:00
|
|
|
{
|
|
|
|
}
|
2014-01-10 23:47:58 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
string path() {
|
|
|
|
return path_join(path_, entry_->d_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void current_entry_set(const struct dirent *entry)
|
|
|
|
{
|
|
|
|
entry_ = entry;
|
|
|
|
}
|
|
|
|
protected:
|
|
|
|
const string& path_;
|
|
|
|
const struct dirent *entry_;
|
|
|
|
};
|
|
|
|
|
|
|
|
directory_iterator()
|
|
|
|
: path_info_(""),
|
|
|
|
name_list_(NULL),
|
|
|
|
num_entries_(-1),
|
|
|
|
cur_entry_(-1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-11 14:50:10 +00:00
|
|
|
explicit directory_iterator(const string& path)
|
2016-02-05 08:09:39 +00:00
|
|
|
: path_(path),
|
|
|
|
path_info_(path_),
|
|
|
|
cur_entry_(0)
|
|
|
|
{
|
|
|
|
num_entries_ = scandir(path.c_str(),
|
|
|
|
&name_list_,
|
|
|
|
NULL,
|
|
|
|
alphasort);
|
|
|
|
if(num_entries_ < 0) {
|
|
|
|
perror("scandir");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
skip_dots();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
~directory_iterator()
|
|
|
|
{
|
|
|
|
destroy_name_list();
|
|
|
|
}
|
|
|
|
|
|
|
|
directory_iterator& operator++()
|
|
|
|
{
|
|
|
|
step();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
path_info* operator-> ()
|
|
|
|
{
|
|
|
|
path_info_.current_entry_set(name_list_[cur_entry_]);
|
|
|
|
return &path_info_;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool operator!=(const directory_iterator& other)
|
|
|
|
{
|
|
|
|
return name_list_ != other.name_list_;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
bool step()
|
|
|
|
{
|
|
|
|
if(do_step()) {
|
|
|
|
return skip_dots();
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool do_step()
|
|
|
|
{
|
|
|
|
++cur_entry_;
|
|
|
|
if(cur_entry_ >= num_entries_) {
|
|
|
|
destroy_name_list();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Skip . and .. folders. */
|
|
|
|
bool skip_dots()
|
|
|
|
{
|
|
|
|
while(strcmp(name_list_[cur_entry_]->d_name, ".") == 0 ||
|
|
|
|
strcmp(name_list_[cur_entry_]->d_name, "..") == 0)
|
|
|
|
{
|
|
|
|
if(!step()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void destroy_name_list()
|
|
|
|
{
|
|
|
|
if(name_list_ == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(int i = 0; i < num_entries_; ++i) {
|
|
|
|
free(name_list_[i]);
|
|
|
|
}
|
|
|
|
free(name_list_);
|
|
|
|
name_list_ = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
string path_;
|
|
|
|
path_info path_info_;
|
|
|
|
struct dirent **name_list_;
|
|
|
|
int num_entries_, cur_entry_;
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
size_t find_last_slash(const string& path)
|
2014-01-10 23:47:58 +00:00
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
for(size_t i = 0; i < path.size(); ++i) {
|
|
|
|
size_t index = path.size() - 1 - i;
|
|
|
|
#ifdef _WIN32
|
|
|
|
if(path[index] == DIR_SEP || path[index] == DIR_SEP_ALT)
|
|
|
|
#else
|
|
|
|
if(path[index] == DIR_SEP)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return string::npos;
|
2014-01-10 23:47:58 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
} /* namespace */
|
|
|
|
|
2015-01-31 10:40:09 +00:00
|
|
|
static char *path_specials(const string& sub)
|
|
|
|
{
|
|
|
|
static bool env_init = false;
|
|
|
|
static char *env_shader_path;
|
2017-03-31 08:12:13 +00:00
|
|
|
static char *env_source_path;
|
2015-01-31 10:40:09 +00:00
|
|
|
if(!env_init) {
|
|
|
|
env_shader_path = getenv("CYCLES_SHADER_PATH");
|
2017-03-31 08:12:13 +00:00
|
|
|
/* NOTE: It is KERNEL in env variable for compatibility reasons. */
|
|
|
|
env_source_path = getenv("CYCLES_KERNEL_PATH");
|
2015-01-31 10:40:09 +00:00
|
|
|
env_init = true;
|
|
|
|
}
|
|
|
|
if(env_shader_path != NULL && sub == "shader") {
|
|
|
|
return env_shader_path;
|
|
|
|
}
|
2017-03-31 08:12:13 +00:00
|
|
|
else if(env_shader_path != NULL && sub == "source") {
|
|
|
|
return env_source_path;
|
2015-01-31 10:40:09 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-09-05 14:41:08 +00:00
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
|
|
static string path_xdg_cache_get()
|
|
|
|
{
|
|
|
|
const char *home = getenv("XDG_CACHE_HOME");
|
|
|
|
if(home) {
|
|
|
|
return string(home);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
home = getenv("HOME");
|
|
|
|
if(home == NULL) {
|
|
|
|
home = getpwuid(getuid())->pw_dir;
|
|
|
|
}
|
|
|
|
return path_join(string(home), ".cache");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-09-09 12:04:39 +00:00
|
|
|
void path_init(const string& path, const string& user_path)
|
2011-04-27 11:58:34 +00:00
|
|
|
{
|
|
|
|
cached_path = path;
|
2011-09-09 12:04:39 +00:00
|
|
|
cached_user_path = user_path;
|
2016-04-01 18:37:24 +00:00
|
|
|
|
|
|
|
#ifdef _MSC_VER
|
|
|
|
// workaround for https://svn.boost.org/trac/boost/ticket/6320
|
|
|
|
// indirectly init boost codec here since it's not thread safe, and can
|
|
|
|
// cause crashes when it happens in multithreaded image load
|
|
|
|
OIIO::Filesystem::exists(path);
|
|
|
|
#endif
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string path_get(const string& sub)
|
|
|
|
{
|
2015-01-31 10:40:09 +00:00
|
|
|
char *special = path_specials(sub);
|
|
|
|
if(special != NULL)
|
|
|
|
return special;
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
if(cached_path == "")
|
|
|
|
cached_path = path_dirname(Sysutil::this_program_path());
|
|
|
|
|
|
|
|
return path_join(cached_path, sub);
|
|
|
|
}
|
|
|
|
|
2011-09-09 12:04:39 +00:00
|
|
|
string path_user_get(const string& sub)
|
|
|
|
{
|
|
|
|
if(cached_user_path == "")
|
|
|
|
cached_user_path = path_dirname(Sysutil::this_program_path());
|
|
|
|
|
|
|
|
return path_join(cached_user_path, sub);
|
|
|
|
}
|
|
|
|
|
2016-09-05 14:41:08 +00:00
|
|
|
string path_cache_get(const string& sub)
|
|
|
|
{
|
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
|
|
if(cached_xdg_cache_path == "") {
|
|
|
|
cached_xdg_cache_path = path_xdg_cache_get();
|
|
|
|
}
|
|
|
|
string result = path_join(cached_xdg_cache_path, "cycles");
|
|
|
|
return path_join(result, sub);
|
|
|
|
#else
|
|
|
|
/* TODO(sergey): What that should be on Windows? */
|
|
|
|
return path_user_get(path_join("cache", sub));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(__linux__) || defined(__APPLE__)
|
|
|
|
string path_xdg_home_get(const string& sub = "");
|
|
|
|
#endif
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
string path_filename(const string& path)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
size_t index = find_last_slash(path);
|
|
|
|
if(index != string::npos) {
|
|
|
|
/* Corner cases to match boost behavior. */
|
|
|
|
#ifndef _WIN32
|
|
|
|
if(index == 0 && path.size() == 1) {
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if(index == path.size() - 1) {
|
|
|
|
#ifdef _WIN32
|
|
|
|
if(index == 2) {
|
|
|
|
return string(1, DIR_SEP);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return ".";
|
|
|
|
}
|
|
|
|
return path.substr(index + 1, path.size() - index - 1);
|
|
|
|
}
|
|
|
|
return path;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string path_dirname(const string& path)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
size_t index = find_last_slash(path);
|
|
|
|
if(index != string::npos) {
|
|
|
|
#ifndef _WIN32
|
|
|
|
if(index == 0 && path.size() > 1) {
|
|
|
|
return string(1, DIR_SEP);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return path.substr(0, index);
|
|
|
|
}
|
|
|
|
return "";
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string path_join(const string& dir, const string& file)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
if(dir.size() == 0) {
|
|
|
|
return file;
|
|
|
|
}
|
|
|
|
if(file.size() == 0) {
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
string result = dir;
|
|
|
|
#ifndef _WIN32
|
|
|
|
if(result[result.size() - 1] != DIR_SEP &&
|
|
|
|
file[0] != DIR_SEP)
|
|
|
|
#else
|
|
|
|
if(result[result.size() - 1] != DIR_SEP &&
|
|
|
|
result[result.size() - 1] != DIR_SEP_ALT &&
|
|
|
|
file[0] != DIR_SEP &&
|
|
|
|
file[0] != DIR_SEP_ALT)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
result += DIR_SEP;
|
|
|
|
}
|
|
|
|
result += file;
|
|
|
|
return result;
|
2011-04-27 11:58:34 +00:00
|
|
|
}
|
|
|
|
|
2011-09-08 18:58:07 +00:00
|
|
|
string path_escape(const string& path)
|
|
|
|
{
|
|
|
|
string result = path;
|
2016-02-05 08:09:39 +00:00
|
|
|
string_replace(result, " ", "\\ ");
|
2011-09-08 18:58:07 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2014-03-21 16:22:41 +00:00
|
|
|
bool path_is_relative(const string& path)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
# ifdef HAVE_SHLWAPI_H
|
|
|
|
return PathIsRelative(path.c_str());
|
|
|
|
# else /* HAVE_SHLWAPI_H */
|
|
|
|
if(path.size() >= 3) {
|
|
|
|
return !(((path[0] >= 'a' && path[0] <= 'z') ||
|
|
|
|
(path[0] >= 'A' && path[0] <= 'Z')) &&
|
|
|
|
path[1] == ':' && path[2] == DIR_SEP);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
# endif /* HAVE_SHLWAPI_H */
|
|
|
|
#else /* _WIN32 */
|
|
|
|
if(path.size() == 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
return path[0] != DIR_SEP;
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
/* Add a slash if the UNC path points to a share. */
|
|
|
|
static string path_unc_add_slash_to_share(const string& path)
|
|
|
|
{
|
|
|
|
size_t slash_after_server = path.find(DIR_SEP, 2);
|
|
|
|
if(slash_after_server != string::npos) {
|
|
|
|
size_t slash_after_share = path.find(DIR_SEP,
|
|
|
|
slash_after_server + 1);
|
|
|
|
if(slash_after_share == string::npos) {
|
|
|
|
return path + DIR_SEP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Convert:
|
|
|
|
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
|
|
|
|
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
|
|
|
|
*/
|
|
|
|
static string path_unc_to_short(const string& path)
|
|
|
|
{
|
|
|
|
size_t len = path.size();
|
|
|
|
if((len > 3) &&
|
|
|
|
(path[0] == DIR_SEP) &&
|
|
|
|
(path[1] == DIR_SEP) &&
|
|
|
|
(path[2] == '?') &&
|
|
|
|
((path[3] == DIR_SEP) || (path[3] == DIR_SEP_ALT)))
|
|
|
|
{
|
|
|
|
if((len > 5) && (path[5] == ':')) {
|
|
|
|
return path.substr(4, len - 4);
|
|
|
|
}
|
2016-04-13 06:58:52 +00:00
|
|
|
else if((len > 7) &&
|
|
|
|
(path.substr(4, 3) == "UNC") &&
|
|
|
|
((path[7] == DIR_SEP) || (path[7] == DIR_SEP_ALT)))
|
2016-02-05 08:09:39 +00:00
|
|
|
{
|
|
|
|
return "\\\\" + path.substr(8, len - 8);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
static string path_cleanup_unc(const string& path)
|
|
|
|
{
|
|
|
|
string result = path_unc_to_short(path);
|
|
|
|
if(path.size() > 2) {
|
|
|
|
/* It's possible path is now a non-UNC. */
|
|
|
|
if(result[0] == DIR_SEP && result[1] == DIR_SEP) {
|
|
|
|
return path_unc_add_slash_to_share(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make path compatible for stat() functions. */
|
|
|
|
static string path_make_compatible(const string& path)
|
|
|
|
{
|
|
|
|
string result = path;
|
2016-02-12 19:21:13 +00:00
|
|
|
/* In Windows stat() doesn't recognize dir ending on a slash. */
|
2016-02-05 08:09:39 +00:00
|
|
|
if(result.size() > 3 && result[result.size() - 1] == DIR_SEP) {
|
2016-02-12 19:21:13 +00:00
|
|
|
result.resize(result.size() - 1);
|
2016-02-05 08:09:39 +00:00
|
|
|
}
|
|
|
|
/* Clean up UNC path. */
|
|
|
|
if((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) {
|
|
|
|
result = path_cleanup_unc(result);
|
|
|
|
}
|
|
|
|
/* Make sure volume-only path ends up wit ha directory separator. */
|
|
|
|
if(result.size() == 2 && result[1] == ':') {
|
|
|
|
result += DIR_SEP;
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int path_wstat(const wstring& path_wc, path_stat_t *st)
|
|
|
|
{
|
|
|
|
#if defined(_MSC_VER) || defined(__MINGW64__)
|
|
|
|
return _wstat64(path_wc.c_str(), st);
|
|
|
|
#elif defined(__MINGW32__)
|
|
|
|
return _wstati64(path_wc.c_str(), st);
|
|
|
|
#else
|
|
|
|
return _wstat(path_wc.c_str(), st);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int path_stat(const string& path, path_stat_t *st)
|
|
|
|
{
|
|
|
|
wstring path_wc = string_to_wstring(path);
|
|
|
|
return path_wstat(path_wc, st);
|
|
|
|
}
|
|
|
|
#else /* _WIN32 */
|
|
|
|
static int path_stat(const string& path, path_stat_t *st)
|
|
|
|
{
|
|
|
|
return stat(path.c_str(), st);
|
|
|
|
}
|
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
|
|
size_t path_file_size(const string& path)
|
|
|
|
{
|
|
|
|
path_stat_t st;
|
|
|
|
if(path_stat(path, &st) != 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return st.st_size;
|
2014-03-21 16:22:41 +00:00
|
|
|
}
|
|
|
|
|
2011-09-08 18:58:07 +00:00
|
|
|
bool path_exists(const string& path)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
string fixed_path = path_make_compatible(path);
|
|
|
|
wstring path_wc = string_to_wstring(fixed_path);
|
|
|
|
path_stat_t st;
|
|
|
|
if(path_wstat(path_wc, &st) != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return st.st_mode != 0;
|
|
|
|
#else /* _WIN32 */
|
|
|
|
struct stat st;
|
|
|
|
if(stat(path.c_str(), &st) != 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return st.st_mode != 0;
|
|
|
|
#endif /* _WIN32 */
|
2011-09-08 18:58:07 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
bool path_is_directory(const string& path)
|
2011-09-03 10:49:54 +00:00
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
path_stat_t st;
|
|
|
|
if(path_stat(path, &st) != 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return S_ISDIR(st.st_mode);
|
|
|
|
}
|
2014-01-10 23:47:58 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
static void path_files_md5_hash_recursive(MD5Hash& hash, const string& dir)
|
|
|
|
{
|
|
|
|
if(path_exists(dir)) {
|
|
|
|
directory_iterator it(dir), it_end;
|
2011-09-03 10:49:54 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
for(; it != it_end; ++it) {
|
|
|
|
if(path_is_directory(it->path())) {
|
|
|
|
path_files_md5_hash_recursive(hash, it->path());
|
2011-09-03 10:49:54 +00:00
|
|
|
}
|
|
|
|
else {
|
2016-02-05 08:09:39 +00:00
|
|
|
string filepath = it->path();
|
2011-09-03 10:49:54 +00:00
|
|
|
|
|
|
|
hash.append((const uint8_t*)filepath.c_str(), filepath.size());
|
|
|
|
hash.append_file(filepath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-09-27 19:35:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
string path_files_md5_hash(const string& dir)
|
|
|
|
{
|
|
|
|
/* computes md5 hash of all files in the directory */
|
|
|
|
MD5Hash hash;
|
|
|
|
|
|
|
|
path_files_md5_hash_recursive(hash, dir);
|
2011-09-03 10:49:54 +00:00
|
|
|
|
|
|
|
return hash.get_hex();
|
|
|
|
}
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
static bool create_directories_recursivey(const string& path)
|
2011-09-09 12:04:39 +00:00
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
if(path_is_directory(path)) {
|
|
|
|
/* Directory already exists, nothing to do. */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(path_exists(path)) {
|
|
|
|
/* File exists and it's not a directory. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
string parent = path_dirname(path);
|
|
|
|
if(parent.size() > 0 && parent != path) {
|
|
|
|
if(!create_directories_recursivey(parent)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-23 12:58:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
wstring path_wc = string_to_wstring(path);
|
|
|
|
return _wmkdir(path_wc.c_str()) == 0;
|
|
|
|
#else
|
2016-02-05 08:09:39 +00:00
|
|
|
return mkdir(path.c_str(), 0777) == 0;
|
2016-03-23 12:58:31 +00:00
|
|
|
#endif
|
2016-02-05 08:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void path_create_directories(const string& filepath)
|
|
|
|
{
|
|
|
|
string path = path_dirname(filepath);
|
|
|
|
create_directories_recursivey(path);
|
2011-09-12 13:13:56 +00:00
|
|
|
}
|
2011-09-09 12:04:39 +00:00
|
|
|
|
2011-09-12 13:13:56 +00:00
|
|
|
bool path_write_binary(const string& path, const vector<uint8_t>& binary)
|
|
|
|
{
|
|
|
|
path_create_directories(path);
|
|
|
|
|
|
|
|
/* write binary file from memory */
|
2014-01-10 23:47:58 +00:00
|
|
|
FILE *f = path_fopen(path, "wb");
|
2011-09-09 12:04:39 +00:00
|
|
|
|
|
|
|
if(!f)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if(binary.size() > 0)
|
|
|
|
fwrite(&binary[0], sizeof(uint8_t), binary.size(), f);
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-05-27 16:21:07 +00:00
|
|
|
bool path_write_text(const string& path, string& text)
|
|
|
|
{
|
|
|
|
vector<uint8_t> binary(text.length(), 0);
|
|
|
|
std::copy(text.begin(), text.end(), binary.begin());
|
|
|
|
|
|
|
|
return path_write_binary(path, binary);
|
|
|
|
}
|
|
|
|
|
2011-09-09 12:04:39 +00:00
|
|
|
bool path_read_binary(const string& path, vector<uint8_t>& binary)
|
|
|
|
{
|
|
|
|
/* read binary file into memory */
|
2014-01-10 23:47:58 +00:00
|
|
|
FILE *f = path_fopen(path, "rb");
|
2011-09-09 12:04:39 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
if(!f) {
|
|
|
|
binary.resize(0);
|
2011-09-09 12:04:39 +00:00
|
|
|
return false;
|
2016-02-05 08:09:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
binary.resize(path_file_size(path));
|
2011-09-09 12:04:39 +00:00
|
|
|
|
|
|
|
if(binary.size() == 0) {
|
|
|
|
fclose(f);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(fread(&binary[0], sizeof(uint8_t), binary.size(), f) != binary.size()) {
|
|
|
|
fclose(f);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
bool path_read_text(const string& path, string& text)
|
2011-11-22 16:38:58 +00:00
|
|
|
{
|
|
|
|
vector<uint8_t> binary;
|
|
|
|
|
|
|
|
if(!path_exists(path) || !path_read_binary(path, binary))
|
|
|
|
return false;
|
2013-05-27 16:21:07 +00:00
|
|
|
|
2011-11-22 16:38:58 +00:00
|
|
|
const char *str = (const char*)&binary[0];
|
|
|
|
size_t size = binary.size();
|
|
|
|
text = string(str, size);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-11-03 14:32:35 +00:00
|
|
|
uint64_t path_modified_time(const string& path)
|
|
|
|
{
|
2016-02-05 08:09:39 +00:00
|
|
|
path_stat_t st;
|
|
|
|
if(path_stat(path, &st) != 0) {
|
2016-11-12 16:20:40 +00:00
|
|
|
return 0;
|
2016-02-05 08:09:39 +00:00
|
|
|
}
|
2016-11-12 16:20:40 +00:00
|
|
|
return st.st_mtime;
|
2012-11-03 14:32:35 +00:00
|
|
|
}
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
bool path_remove(const string& path)
|
|
|
|
{
|
|
|
|
return remove(path.c_str()) == 0;
|
|
|
|
}
|
|
|
|
|
2017-04-28 15:46:11 +00:00
|
|
|
static string line_directive(const string& base, const string& path, int line)
|
2016-07-30 23:54:05 +00:00
|
|
|
{
|
|
|
|
string escaped_path = path;
|
2017-04-28 15:46:11 +00:00
|
|
|
/* First we make path relative. */
|
|
|
|
if(string_startswith(escaped_path, base.c_str())) {
|
|
|
|
const string base_file = path_filename(base);
|
|
|
|
const size_t base_len = base.length();
|
|
|
|
escaped_path = base_file + escaped_path.substr(base_len,
|
|
|
|
escaped_path.length() - base_len);
|
|
|
|
}
|
|
|
|
/* Second, we replace all unsafe characters. */
|
2016-07-30 23:54:05 +00:00
|
|
|
string_replace(escaped_path, "\"", "\\\"");
|
|
|
|
string_replace(escaped_path, "\'", "\\\'");
|
|
|
|
string_replace(escaped_path, "\?", "\\\?");
|
|
|
|
string_replace(escaped_path, "\\", "\\\\");
|
|
|
|
return string_printf("#line %d \"%s\"", line, escaped_path.c_str());
|
|
|
|
}
|
|
|
|
|
2017-04-28 15:46:11 +00:00
|
|
|
static string path_source_replace_includes_recursive(
|
|
|
|
const string& base,
|
|
|
|
const string& source,
|
2017-05-17 14:58:20 +00:00
|
|
|
const string& source_filepath)
|
2011-11-22 16:38:58 +00:00
|
|
|
{
|
2016-02-12 17:33:43 +00:00
|
|
|
/* Our own little c preprocessor that replaces #includes with the file
|
2017-04-28 15:46:11 +00:00
|
|
|
* contents, to work around issue of OpenCL drivers not supporting
|
2016-02-12 17:33:43 +00:00
|
|
|
* include paths with spaces in them.
|
|
|
|
*/
|
|
|
|
|
|
|
|
string result = "";
|
|
|
|
vector<string> lines;
|
2016-07-30 14:54:48 +00:00
|
|
|
string_split(lines, source, "\n", false);
|
2016-02-12 17:33:43 +00:00
|
|
|
|
|
|
|
for(size_t i = 0; i < lines.size(); ++i) {
|
|
|
|
string line = lines[i];
|
|
|
|
if(line[0] == '#') {
|
|
|
|
string token = string_strip(line.substr(1, line.size() - 1));
|
|
|
|
if(string_startswith(token, "include")) {
|
|
|
|
token = string_strip(token.substr(7, token.size() - 7));
|
|
|
|
if(token[0] == '"') {
|
2017-05-17 14:58:20 +00:00
|
|
|
const size_t n_start = 1;
|
|
|
|
const size_t n_end = token.find("\"", n_start);
|
|
|
|
const string filename = token.substr(n_start, n_end - n_start);
|
|
|
|
string filepath = path_join(base, filename);
|
|
|
|
if(!path_exists(filepath)) {
|
|
|
|
filepath = path_join(path_dirname(source_filepath),
|
|
|
|
filename);
|
|
|
|
}
|
|
|
|
string text;
|
2016-02-12 17:33:43 +00:00
|
|
|
if(path_read_text(filepath, text)) {
|
2017-05-17 14:58:20 +00:00
|
|
|
text = path_source_replace_includes_recursive(
|
|
|
|
base, text, filepath);
|
2016-07-30 23:54:05 +00:00
|
|
|
/* Use line directives for better error messages. */
|
2017-04-28 15:46:11 +00:00
|
|
|
line = line_directive(base, filepath, 1)
|
2016-07-30 23:54:05 +00:00
|
|
|
+ token.replace(0, n_end + 1, "\n" + text + "\n")
|
2017-05-17 14:58:20 +00:00
|
|
|
+ line_directive(base, source_filepath, i + 1);
|
2016-02-12 17:33:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-22 16:38:58 +00:00
|
|
|
}
|
2016-02-12 17:33:43 +00:00
|
|
|
result += line + "\n";
|
2011-11-22 16:38:58 +00:00
|
|
|
}
|
|
|
|
|
2016-02-12 17:33:43 +00:00
|
|
|
return result;
|
2011-11-22 16:38:58 +00:00
|
|
|
}
|
|
|
|
|
2017-04-28 15:46:11 +00:00
|
|
|
string path_source_replace_includes(const string& source,
|
|
|
|
const string& path,
|
|
|
|
const string& source_filename)
|
|
|
|
{
|
2017-05-17 14:58:20 +00:00
|
|
|
return path_source_replace_includes_recursive(
|
|
|
|
path,
|
|
|
|
source,
|
|
|
|
path_join(path, source_filename));
|
2017-04-28 15:46:11 +00:00
|
|
|
}
|
|
|
|
|
2014-01-10 23:47:58 +00:00
|
|
|
FILE *path_fopen(const string& path, const string& mode)
|
|
|
|
{
|
2016-03-23 12:58:31 +00:00
|
|
|
#ifdef _WIN32
|
|
|
|
wstring path_wc = string_to_wstring(path);
|
|
|
|
wstring mode_wc = string_to_wstring(mode);
|
|
|
|
return _wfopen(path_wc.c_str(), mode_wc.c_str());
|
|
|
|
#else
|
2014-01-10 23:47:58 +00:00
|
|
|
return fopen(path.c_str(), mode.c_str());
|
2016-03-23 12:58:31 +00:00
|
|
|
#endif
|
2014-01-10 23:47:58 +00:00
|
|
|
}
|
|
|
|
|
2014-01-23 00:13:09 +00:00
|
|
|
void path_cache_clear_except(const string& name, const set<string>& except)
|
|
|
|
{
|
|
|
|
string dir = path_user_get("cache");
|
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
if(path_exists(dir)) {
|
|
|
|
directory_iterator it(dir), it_end;
|
2014-01-23 00:13:09 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
for(; it != it_end; ++it) {
|
|
|
|
string filename = path_filename(it->path());
|
2014-01-23 00:13:09 +00:00
|
|
|
|
2016-02-05 08:09:39 +00:00
|
|
|
if(string_startswith(filename, name.c_str()))
|
2014-01-23 00:13:09 +00:00
|
|
|
if(except.find(filename) == except.end())
|
2016-02-05 08:09:39 +00:00
|
|
|
path_remove(it->path());
|
2014-01-23 00:13:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2011-04-27 11:58:34 +00:00
|
|
|
CCL_NAMESPACE_END
|
|
|
|
|