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) {
179 if (documents_path &&
BLI_is_dir(documents_path)) {
193 BLI_path_join(try_documents_path,
sizeof(try_documents_path), home_path,
N_(
"Documents"));
207 if (caches_root_path ==
nullptr || !
BLI_is_dir(caches_root_path)) {
210 if (caches_root_path ==
nullptr || !
BLI_is_dir(caches_root_path)) {
216 path, path_maxncpy, caches_root_path,
"Blender Foundation",
"Blender",
"Cache",
SEP_STR);
217#elif defined(__APPLE__)
232 wchar_t wpath[MAX_PATH];
233 if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) {
236#elif defined(__APPLE__)
238 BLI_path_join(test_dir,
sizeof(test_dir), home_dir,
"Library/Fonts");
241 STRNCPY(test_dir,
"/usr/share/fonts");
273 size_t targetpath_maxncpy,
274 const bool check_is_dir,
275 const char *path_base,
276 const char *folder_name,
277 const char *subfolder_name)
282 BLI_assert(!(folder_name ==
nullptr && (subfolder_name !=
nullptr)));
283 const char *path_array[] = {path_base, folder_name, subfolder_name};
284 const int path_array_num = (folder_name ? (subfolder_name ? 3 : 2) : 1);
286 if (check_is_dir ==
false) {
287 CLOG_INFO(&
LOG, 3,
"using without test: '%s'", targetpath);
300 targetpath[0] =
'\0';
312static bool test_env_path(
char *path,
const char *envvar,
const bool check_is_dir)
316 const char *env_path = envvar ?
BLI_getenv(envvar) :
nullptr;
323 if (check_is_dir ==
false) {
324 CLOG_INFO(&
LOG, 3,
"using env '%s' without test: '%s'", envvar, env_path);
329 CLOG_INFO(&
LOG, 3,
"env '%s' found: %s", envvar, env_path);
333 CLOG_INFO(&
LOG, 3,
"env '%s' missing: %s", envvar, env_path);
354 size_t targetpath_maxncpy,
355 const char *folder_name,
356 const char *subfolder_name,
358 const bool check_is_dir)
364 "folder='%s', subfolder='%s'",
369 const char *path_array[] = {folder_name, subfolder_name};
370 const int path_array_num = subfolder_name ? 2 : 1;
379 const char *path_base =
g_app.program_dirname;
380#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
384 char osx_resourses[
FILE_MAX + 4 + 9];
385 BLI_path_join(osx_resourses,
sizeof(osx_resourses),
g_app.program_dirname,
"..",
"Resources");
388 path_base = osx_resourses;
395 (version) ? relfolder :
nullptr);
398 size_t targetpath_maxncpy,
399 const char *folder_name,
400 const char *subfolder_name)
403 const bool check_is_dir =
true;
405 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
418 size_t targetpath_maxncpy,
419 const char *subfolder_name,
421 const bool check_is_dir)
428 targetpath, targetpath_maxncpy, check_is_dir, user_path, subfolder_name,
nullptr);
433 size_t targetpath_maxncpy,
434 const char *subfolder_name,
437 const bool check_is_dir =
true;
439 targetpath, targetpath_maxncpy, subfolder_name, envvar, check_is_dir);
444 const bool check_is_dir)
447 const char *env_path = envvar ?
BLI_getenv(envvar) :
nullptr;
453 const char separator =
';';
455 const char separator =
':';
458 const char *char_begin = env_path;
460 while (char_begin[0]) {
461 const size_t base_path_len = char_end - char_begin;
462 if (base_path_len > 0 && base_path_len <
PATH_MAX) {
464 memcpy(base_path, char_begin, base_path_len);
465 base_path[base_path_len] =
'\0';
468 if (
test_path(path,
sizeof(path), check_is_dir, base_path, subfolder_name,
nullptr)) {
472 char_begin = char_end[0] ? char_end + 1 : char_end;
490 size_t targetpath_maxncpy,
491 const char *folder_name,
492 const char *subfolder_name,
494 const bool check_is_dir)
499 if (
test_env_path(user_path,
"BLENDER_USER_RESOURCES", check_is_dir)) {
503 else if (
get_path_local_ex(user_path,
sizeof(user_path),
"portable",
nullptr, 0,
true)) {
510 if (user_base_path) {
511 STRNCPY(user_path, user_base_path);
521 "'%s', folder='%s', subfolder='%s'",
528 targetpath, targetpath_maxncpy, check_is_dir, user_path, folder_name, subfolder_name);
531 size_t targetpath_maxncpy,
532 const char *folder_name,
533 const char *subfolder_name)
536 const bool check_is_dir =
true;
538 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
552 size_t targetpath_maxncpy,
553 const char *folder_name,
554 const char *subfolder_name,
556 const bool check_is_dir)
560 if (
test_env_path(system_path,
"BLENDER_SYSTEM_RESOURCES", check_is_dir)) {
564 system_path[0] =
'\0';
566 if (system_base_path) {
567 STRNCPY(system_path, system_base_path);
571 if (!system_path[0]) {
577 "'%s', folder='%s', subfolder='%s'",
584 targetpath, targetpath_maxncpy, check_is_dir, system_path, folder_name, subfolder_name);
588 size_t targetpath_maxncpy,
589 const char *folder_name,
590 const char *subfolder_name)
593 const bool check_is_dir =
true;
595 targetpath, targetpath_maxncpy, folder_name, subfolder_name, version, check_is_dir);
605 const char *subfolder,
614 if (
get_path_user(path, path_maxncpy,
"datafiles", subfolder)) {
632 if (
get_path_user(path, path_maxncpy,
"datafiles", subfolder)) {
653 if (
get_path_user(path, path_maxncpy,
"config", subfolder)) {
662 if (
get_path_user(path, path_maxncpy,
"scripts", subfolder)) {
680 if (
get_path_user(path, path_maxncpy,
"extensions", subfolder)) {
692 if (
get_path_local(path, path_maxncpy,
"extensions", subfolder)) {
727 const char *subfolder)
731 const bool check_is_dir =
false;
736 path,
sizeof(path), subfolder,
"BLENDER_USER_DATAFILES", check_is_dir))
740 get_path_user_ex(path,
sizeof(path),
"datafiles", subfolder, version, check_is_dir);
744 path,
sizeof(path), subfolder,
"BLENDER_USER_CONFIG", check_is_dir))
748 get_path_user_ex(path,
sizeof(path),
"config", subfolder, version, check_is_dir);
752 path,
sizeof(path), subfolder,
"BLENDER_USER_SCRIPTS", check_is_dir))
756 get_path_user_ex(path,
sizeof(path),
"scripts", subfolder, version, check_is_dir);
760 path,
sizeof(path), subfolder,
"BLENDER_USER_EXTENSIONS", check_is_dir))
764 get_path_user_ex(path,
sizeof(path),
"extensions", subfolder, version, check_is_dir);
771 if (
'\0' == path[0]) {
792 if (!path.has_value()) {
794 if (path.has_value()) {
803 const bool check_is_dir,
810 ok =
get_path_user_ex(path,
sizeof(path),
nullptr,
nullptr, version, check_is_dir);
813 ok =
get_path_local_ex(path,
sizeof(path),
nullptr,
nullptr, version, check_is_dir);
831 const bool check_is_dir)
844#ifndef WITH_PYTHON_MODULE
858 const size_t program_filepath_maxncpy,
859 const char *program_name)
864 const char *path =
nullptr;
865 path = br_find_exe(
nullptr);
877 if (GetModuleFileNameW(0, fullname_16, program_filepath_maxncpy)) {
881 "path can't be found: \"%.*s\"",
882 int(program_filepath_maxncpy),
885 "path contains invalid characters or is too long (see console)",
898 if (program_name && program_name[0]) {
901 if (program_name[0] ==
'.') {
904 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy);
911 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy);
931#ifdef WITH_PYTHON_MODULE
938 if (
g_app.program_dirname[0] ==
'\0') {
942 g_app.program_filepath,
g_app.program_dirname,
sizeof(
g_app.program_dirname));
943 g_app.program_filepath[0] =
'\0';
948 g_app.program_filepath,
g_app.program_dirname,
sizeof(
g_app.program_dirname));
954#ifndef WITH_PYTHON_MODULE
957 return g_app.program_filepath;
963 return g_app.program_dirname;
967 const size_t program_filepath_maxncpy,
968 const int version_major,
969 const int version_minor)
973#ifdef PYTHON_EXECUTABLE_NAME
975 const char *python_build_def =
STRINGIFY(PYTHON_EXECUTABLE_NAME);
977 const char *basename =
"python";
978#if defined(WIN32) && !defined(NDEBUG)
979 const char *basename_debug =
"python_d";
981 char python_version[16];
983 const char *python_names[] = {
984#ifdef PYTHON_EXECUTABLE_NAME
987#if defined(WIN32) && !defined(NDEBUG)
993 bool is_found =
false;
995 SNPRINTF(python_version,
"%s%d.%d", basename, version_major, version_minor);
1000 if (python_bin_dir.has_value()) {
1004 program_filepath, program_filepath_maxncpy, python_bin_dir->c_str(), python_names[
i]);
1008 BLI_path_program_extensions_add_win32(
program_filepath, program_filepath_maxncpy)
1021 if (is_found ==
false) {
1030 if (is_found ==
false) {
1050 "startup" SEP_STR "bl_app_templates_user",
1054 directories.
append(temp_dir);
1059 "startup" SEP_STR "bl_app_templates_system",
"BLENDER_SYSTEM_SCRIPTS",
true));
1063 "startup" SEP_STR "bl_app_templates_system",
1067 directories.
append(temp_dir);
1082 for (
const std::string &directory : directories) {
1102 app_template, app_template_path,
sizeof(app_template_path)))
1118 for (
const std::string &subdir : directories) {
1121 for (
int f = 0; f < dir_num; f++) {
1151static bool where_is_temp(
char *tempdir,
const size_t tempdir_maxncpy,
const char *userdir)
1161 const size_t tempdir_session_maxncpy,
1162 const char *tempdir)
1164 tempdir_session[0] =
'\0';
1166 const int tempdir_len = strlen(tempdir);
1168 const char *session_name =
"blender_XXXXXX";
1169 const int session_name_len = strlen(session_name);
1173 const int tempdir_session_len_required = tempdir_len + session_name_len + 1;
1175 if (tempdir_session_len_required <= tempdir_session_maxncpy) {
1177 BLI_string_join(tempdir_session, tempdir_session_maxncpy, tempdir, session_name);
1179 const bool needs_create = (_mktemp_s(tempdir_session, tempdir_session_len_required) == 0);
1181 const bool needs_create = (mkdtemp(tempdir_session) ==
nullptr);
1193 CLOG_WARN(&
LOG,
"Could not generate a temp file name for '%s'", tempdir_session);
1212 g_app.temp_dirname_session_can_be_deleted =
false;
1213 for (
int pass = 0; pass < 2; pass += 1) {
1215 g_app.temp_dirname_base,
sizeof(
g_app.temp_dirname_base), pass == 0 ? userdir :
nullptr);
1219 sizeof(
g_app.temp_dirname_session),
1220 g_app.temp_dirname_base))
1223 g_app.temp_dirname_session_can_be_deleted =
true;
1229 if (from_userdir ==
false) {
1234 if (
UNLIKELY(
g_app.temp_dirname_session_can_be_deleted ==
false)) {
1239 "Could not generate a temp session subdirectory, falling back to '%s'",
1240 g_app.temp_dirname_base);
1251 return g_app.temp_dirname_base;
1256 if (
g_app.temp_dirname_session_can_be_deleted ==
false) {
@ BLENDER_USER_EXTENSIONS
@ BLENDER_SYSTEM_DATAFILES
@ BLENDER_SYSTEM_EXTENSIONS
#define BLENDER_USERPREF_FILE
@ BLENDER_RESOURCE_PATH_SYSTEM
@ BLENDER_RESOURCE_PATH_LOCAL
@ BLENDER_RESOURCE_PATH_USER
#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_WARN(clg_ref,...)
#define CLOG_INFO(clg_ref, level,...)
const char * 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)
static struct @004337376000312322276010372351321061214207011145 g_app
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)
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)