42# define _WIN32_IE 0x0501
55#define STR_OR_FALLBACK(a) ((a) ? (a) : _str_null)
88# define ASSERT_IS_INIT() BLI_assert(is_appdir_init)
90# define ASSERT_IS_INIT() ((void)0)
125 static char version_str[5];
127 SNPRINTF(version_str,
"%d.%d", version / 100, version % 100);
145 return documentfolder;
166 if (path ==
nullptr) {
180 if (documents_path &&
BLI_is_dir(documents_path->c_str())) {
194 BLI_path_join(try_documents_path,
sizeof(try_documents_path), home_path,
N_(
"Documents"));
209 if (!caches_root_path || !
BLI_is_dir(caches_root_path->c_str())) {
212 if (!caches_root_path || !
BLI_is_dir(caches_root_path->c_str())) {
219 caches_root_path->c_str(),
220 "Blender Foundation",
224#elif defined(__APPLE__)
239 wchar_t wpath[MAX_PATH];
240 if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) {
243#elif defined(__APPLE__)
245 BLI_path_join(test_dir,
sizeof(test_dir), home_dir,
"Library/Fonts");
248 STRNCPY(test_dir,
"/usr/share/fonts");
280 size_t targetpath_maxncpy,
281 const bool check_is_dir,
282 const char *path_base,
283 const char *folder_name,
284 const char *subfolder_name)
289 BLI_assert(!(folder_name ==
nullptr && (subfolder_name !=
nullptr)));
290 const char *path_array[] = {path_base, folder_name, subfolder_name};
291 const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1);
293 if (check_is_dir ==
false) {
307 targetpath[0] =
'\0';
319static bool test_env_path(
char *path,
const char *envvar,
const bool check_is_dir)
323 const char *env_path = envvar ?
BLI_getenv(envvar) :
nullptr;
330 if (check_is_dir ==
false) {
331 CLOG_DEBUG(&
LOG,
"Using env '%s' (without test): '%s'", envvar, env_path);
361 size_t targetpath_maxncpy,
362 const char *folder_name,
363 const char *subfolder_name,
365 const bool check_is_dir)
370 "Get path local: folder='%s', subfolder='%s'",
375 const char *path_array[] = {folder_name, subfolder_name};
376 const int path_array_num = subfolder_name ? 2 : 1;
385 const char *path_base =
g_app.program_dirname;
386#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
390 char osx_resourses[
FILE_MAX + 4 + 9];
391 BLI_path_join(osx_resourses,
sizeof(osx_resourses),
g_app.program_dirname,
"..",
"Resources");
394 path_base = osx_resourses;
401 (version) ? relfolder :
nullptr);
404 size_t targetpath_maxncpy,
405 const char *folder_name,
406 const char *subfolder_name)
409 const bool check_is_dir =
true;
411 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
424 size_t targetpath_maxncpy,
425 const char *subfolder_name,
427 const bool check_is_dir)
434 targetpath, targetpath_maxncpy, check_is_dir, user_path, subfolder_name,
nullptr);
439 size_t targetpath_maxncpy,
440 const char *subfolder_name,
443 const bool check_is_dir =
true;
445 targetpath, targetpath_maxncpy, subfolder_name, envvar, check_is_dir);
450 const bool check_is_dir)
453 const char *env_path = envvar ?
BLI_getenv(envvar) :
nullptr;
459 const char separator =
';';
461 const char separator =
':';
464 const char *char_begin = env_path;
466 while (char_begin[0]) {
467 const size_t base_path_len = char_end - char_begin;
468 if (base_path_len > 0 && base_path_len <
PATH_MAX) {
470 memcpy(base_path, char_begin, base_path_len);
471 base_path[base_path_len] =
'\0';
474 if (
test_path(path,
sizeof(path), check_is_dir, base_path, subfolder_name,
nullptr)) {
478 char_begin = char_end[0] ? char_end + 1 : char_end;
496 size_t targetpath_maxncpy,
497 const char *folder_name,
498 const char *subfolder_name,
500 const bool check_is_dir)
505 if (
test_env_path(user_path,
"BLENDER_USER_RESOURCES", check_is_dir)) {
509 else if (
get_path_local_ex(user_path,
sizeof(user_path),
"portable",
nullptr, 0,
true)) {
516 if (user_base_path) {
517 STRNCPY(user_path, user_base_path);
526 "Get path user: '%s', folder='%s', subfolder='%s'",
533 targetpath, targetpath_maxncpy, check_is_dir, user_path, folder_name, subfolder_name);
536 size_t targetpath_maxncpy,
537 const char *folder_name,
538 const char *subfolder_name)
541 const bool check_is_dir =
true;
543 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
557 size_t targetpath_maxncpy,
558 const char *folder_name,
559 const char *subfolder_name,
561 const bool check_is_dir)
565 if (
test_env_path(system_path,
"BLENDER_SYSTEM_RESOURCES", check_is_dir)) {
569 system_path[0] =
'\0';
571 if (system_base_path) {
572 STRNCPY(system_path, system_base_path);
576 if (!system_path[0]) {
581 "Get path system: '%s', folder='%s', subfolder='%s'",
588 targetpath, targetpath_maxncpy, check_is_dir, system_path, folder_name, subfolder_name);
592 size_t targetpath_maxncpy,
593 const char *folder_name,
594 const char *subfolder_name)
597 const bool check_is_dir =
true;
599 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
609 const char *subfolder,
618 if (
get_path_user(path, path_maxncpy,
"datafiles", subfolder)) {
636 if (
get_path_user(path, path_maxncpy,
"datafiles", subfolder)) {
657 if (
get_path_user(path, path_maxncpy,
"config", subfolder)) {
666 if (
get_path_user(path, path_maxncpy,
"scripts", subfolder)) {
684 if (
get_path_user(path, path_maxncpy,
"extensions", subfolder)) {
696 if (
get_path_local(path, path_maxncpy,
"extensions", subfolder)) {
731 const char *subfolder)
735 const bool check_is_dir =
false;
740 path,
sizeof(path), subfolder,
"BLENDER_USER_DATAFILES", check_is_dir))
744 get_path_user_ex(path,
sizeof(path),
"datafiles", subfolder, version, check_is_dir);
748 path,
sizeof(path), subfolder,
"BLENDER_USER_CONFIG", check_is_dir))
752 get_path_user_ex(path,
sizeof(path),
"config", subfolder, version, check_is_dir);
756 path,
sizeof(path), subfolder,
"BLENDER_USER_SCRIPTS", check_is_dir))
760 get_path_user_ex(path,
sizeof(path),
"scripts", subfolder, version, check_is_dir);
764 path,
sizeof(path), subfolder,
"BLENDER_USER_EXTENSIONS", check_is_dir))
768 get_path_user_ex(path,
sizeof(path),
"extensions", subfolder, version, check_is_dir);
775 if (
'\0' == path[0]) {
796 if (!path.has_value()) {
798 if (path.has_value()) {
807 const bool check_is_dir,
814 ok =
get_path_user_ex(path,
sizeof(path),
nullptr,
nullptr, version, check_is_dir);
817 ok =
get_path_local_ex(path,
sizeof(path),
nullptr,
nullptr, version, check_is_dir);
835 const bool check_is_dir)
848#ifndef WITH_PYTHON_MODULE
862 const size_t program_filepath_maxncpy,
863 const char *program_name)
868 const char *path =
nullptr;
869 path = br_find_exe(
nullptr);
881 if (GetModuleFileNameW(0, fullname_16, program_filepath_maxncpy)) {
885 "Program path can't be found: \"%.*s\"",
886 int(program_filepath_maxncpy),
889 "path contains invalid characters or is too long (see console)",
902 if (program_name && program_name[0]) {
905 if (program_name[0] ==
'.') {
908 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy);
915 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy);
935#ifdef WITH_PYTHON_MODULE
942 if (
g_app.program_dirname[0] ==
'\0') {
946 g_app.program_filepath,
g_app.program_dirname,
sizeof(
g_app.program_dirname));
947 g_app.program_filepath[0] =
'\0';
952 g_app.program_filepath,
g_app.program_dirname,
sizeof(
g_app.program_dirname));
958#ifndef WITH_PYTHON_MODULE
961 return g_app.program_filepath;
967 return g_app.program_dirname;
971 const size_t program_filepath_maxncpy,
972 const int version_major,
973 const int version_minor)
977#ifdef PYTHON_EXECUTABLE_NAME
979 const char *python_build_def =
STRINGIFY(PYTHON_EXECUTABLE_NAME);
981 const char *basename =
"python";
982#if defined(WIN32) && !defined(NDEBUG)
983 const char *basename_debug =
"python_d";
985 char python_version[16];
987 const char *python_names[] = {
988#ifdef PYTHON_EXECUTABLE_NAME
991#if defined(WIN32) && !defined(NDEBUG)
997 bool is_found =
false;
999 SNPRINTF(python_version,
"%s%d.%d", basename, version_major, version_minor);
1004 if (python_bin_dir.has_value()) {
1008 program_filepath, program_filepath_maxncpy, python_bin_dir->c_str(), python_names[
i]);
1012 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy)
1025 if (is_found ==
false) {
1034 if (is_found ==
false) {
1054 "startup" SEP_STR "bl_app_templates_user",
1058 directories.
append(temp_dir);
1063 "startup" SEP_STR "bl_app_templates_system",
"BLENDER_SYSTEM_SCRIPTS",
true));
1067 "startup" SEP_STR "bl_app_templates_system",
1071 directories.
append(temp_dir);
1086 for (
const std::string &directory : directories) {
1106 app_template, app_template_path,
sizeof(app_template_path)))
1122 for (
const std::string &subdir : directories) {
1125 for (
int f = 0; f < dir_num; f++) {
1154static bool where_is_temp(
char *tempdir,
const size_t tempdir_maxncpy,
const char *userdir)
1164 const size_t tempdir_session_maxncpy,
1165 const char *tempdir)
1167 tempdir_session[0] =
'\0';
1169 const int tempdir_len = strlen(tempdir);
1171 const char *session_name =
"blender_XXXXXX";
1172 const int session_name_len = strlen(session_name);
1176 const int tempdir_session_len_required = tempdir_len + session_name_len + 1;
1178 if (tempdir_session_len_required <= tempdir_session_maxncpy) {
1180 BLI_string_join(tempdir_session, tempdir_session_maxncpy, tempdir, session_name);
1182 const bool needs_create = (_mktemp_s(tempdir_session, tempdir_session_len_required) == 0);
1184 const bool needs_create = (mkdtemp(tempdir_session) ==
nullptr);
1196 CLOG_WARN(&
LOG,
"Could not generate a temp file name for '%s'", tempdir_session);
1210 g_app.temp_dirname_session_can_be_deleted =
false;
1213 int userdir_args_num = userdir ? 2 : 1;
1214 const char *userdir_args[2] = {userdir,
nullptr};
1216 for (
int i = 0;
i < userdir_args_num;
i++) {
1219 sizeof(
g_app.temp_dirname_session),
1220 g_app.temp_dirname_base))
1222 g_app.temp_dirname_session_can_be_deleted =
true;
1228 if (
UNLIKELY(
g_app.temp_dirname_session_can_be_deleted ==
false)) {
1233 "Could not generate a temp session subdirectory, falling back to '%s'",
1234 g_app.temp_dirname_base);
1245 return g_app.temp_dirname_base;
1250 if (
g_app.temp_dirname_session_can_be_deleted ==
false) {
@ BLENDER_RESOURCE_PATH_SYSTEM
@ BLENDER_RESOURCE_PATH_LOCAL
@ BLENDER_RESOURCE_PATH_USER
#define BLENDER_USERPREF_FILE
@ BLENDER_USER_EXTENSIONS
@ BLENDER_SYSTEM_DATAFILES
@ BLENDER_SYSTEM_EXTENSIONS
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
File and directory operations.
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_filelist)
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
bool BLI_is_dir(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BLI_filelist_free(struct direntry *filelist, unsigned int nrentries)
const char * BLI_dir_home(void)
Some types for dealing with directories.
void BLI_kdtree_nd_ free(KDTree *tree)
LinkData * BLI_genericNodeN(void *data)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
bool BLI_path_program_search(char *program_filepath, size_t program_filepath_maxncpy, const char *program_name) ATTR_NONNULL(1
#define BLI_path_join(...)
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILENAME_IS_CURRPAR(_n)
int BLI_path_canonicalize_native(char *path, int path_maxncpy)
void void BLI_path_split_dir_part(const char *filepath, char *dir, size_t dir_maxncpy) ATTR_NONNULL(1
size_t BLI_path_join_array(char *__restrict dst, const size_t dst_maxncpy, const char *path_array[], const int path_array_num) ATTR_NONNULL(1
int BLI_path_slash_ensure(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
bool BLI_path_abs_from_cwd(char *path, size_t path_maxncpy) ATTR_NONNULL(1)
const char * BLI_path_slash_rfind(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
int BLI_path_normalize_native(char *path) ATTR_NONNULL(1)
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
char char size_t char const char * BLI_strchr_or_end(const char *str, char ch) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1)
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t BLI_strncpy_wchar_as_utf8(char *__restrict dst, const wchar_t *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define BLI_string_join(...)
bool void BLI_temp_directory_path_get(char *tempdir, const size_t tempdir_maxncpy) ATTR_NONNULL(1)
bool BLI_temp_directory_path_copy_if_valid(char *tempdir, const size_t tempdir_maxncpy, const char *dirpath) ATTR_NONNULL(1
Compatibility-like things for windows.
void BLI_windows_get_default_root_dir(char root_dir[4])
#define CLOG_ERROR(clg_ref,...)
#define CLOG_DEBUG(clg_ref,...)
#define CLOG_WARN(clg_ref,...)
std::optional< std::string > GHOST_getUserSpecialDir(GHOST_TUserSpecialDirTypes type)
const char * GHOST_getSystemDir(int version, const char *versionstr)
GHOST_TSuccess GHOST_DisposeSystemPaths()
const char * GHOST_getUserDir(int version, const char *versionstr)
@ GHOST_kUserSpecialDirCaches
@ GHOST_kUserSpecialDirDocuments
static const char _str_null[]
void BKE_tempdir_init(const char *userdir)
static bool is_appdir_init
std::optional< std::string > BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
char program_dirname[FILE_MAX]
static bool get_path_user_ex(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name, const int version, const bool check_is_dir)
static bool get_path_environment(char *targetpath, size_t targetpath_maxncpy, const char *subfolder_name, const char *envvar)
std::optional< std::string > BKE_appdir_resource_path_id(const int folder_id, const bool check_is_dir)
const char * BKE_appdir_folder_root()
const char * BKE_tempdir_session()
char temp_dirname_session[FILE_MAX]
std::optional< std::string > BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
bool BKE_appdir_folder_documents(char *dir)
static bool test_env_path(char *path, const char *envvar, const bool check_is_dir)
bool BKE_appdir_app_template_has_userpref(const char *app_template)
const char * BKE_appdir_program_dir()
static bool test_path(char *targetpath, size_t targetpath_maxncpy, const bool check_is_dir, const char *path_base, const char *folder_name, const char *subfolder_name)
bool BKE_appdir_program_python_search(char *program_filepath, const size_t program_filepath_maxncpy, const int version_major, const int version_minor)
static bool get_path_system_ex(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name, const int version, const bool check_is_dir)
void BKE_appdir_program_path_init(const char *argv0)
static bool where_is_temp(char *tempdir, const size_t tempdir_maxncpy, const char *userdir)
static struct @117045314216322207174324056210201300111320007173 g_app
std::optional< std::string > BKE_appdir_resource_path_id_with_version(const int folder_id, const bool check_is_dir, const int version)
const char * BKE_appdir_folder_default_or_root()
bool BKE_appdir_folder_id_ex(const int folder_id, const char *subfolder, char *path, size_t path_maxncpy)
static bool tempdir_session_create(char *tempdir_session, const size_t tempdir_session_maxncpy, const char *tempdir)
static char * blender_version_decimal(const int version)
static blender::Vector< std::string > appdir_app_template_directories()
#define STR_OR_FALLBACK(a)
static bool get_path_local(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name)
static blender::Vector< std::string > get_path_environment_multiple(const char *subfolder_name, const char *envvar, const bool check_is_dir)
bool temp_dirname_session_can_be_deleted
std::optional< std::string > BKE_appdir_folder_id(const int folder_id, const char *subfolder)
bool BKE_appdir_app_template_any()
void BKE_appdir_app_templates(ListBase *templates)
bool BKE_appdir_font_folder_default(char *dir, size_t dir_maxncpy)
bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_maxncpy)
const char * BKE_appdir_folder_default()
static bool get_path_local_ex(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name, const int version, const bool check_is_dir)
const char * BKE_appdir_program_path()
char temp_dirname_base[FILE_MAX]
void BKE_tempdir_session_purge()
static void where_am_i(char *program_filepath, const size_t program_filepath_maxncpy, const char *program_name)
static bool get_path_system(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name)
static bool get_path_user(char *targetpath, size_t targetpath_maxncpy, const char *folder_name, const char *subfolder_name)
char program_filepath[FILE_MAX]
const char * BKE_tempdir_base()
static bool get_path_environment_ex(char *targetpath, size_t targetpath_maxncpy, const char *subfolder_name, const char *envvar, const bool check_is_dir)
bool BKE_appdir_folder_caches(char *path, const size_t path_maxncpy)
void append(const T &value)
void extend(Span< T > array)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8)