Core: make BKE_appdir functions thread safe, using optional<string>

The static variables can cause the wrong path to be used, for example
when asset indexing in a thread affects loading toolbar icons.

Fix #117416: toolbar icon randomly missing

Pull Request: https://projects.blender.org/blender/blender/pulls/117419
This commit is contained in:
Brecht Van Lommel
2024-01-23 18:38:15 +01:00
committed by Brecht Van Lommel
parent 4e483dad4b
commit e0ff7731e0
23 changed files with 173 additions and 147 deletions

View File

@@ -17,11 +17,9 @@ namespace blender::asset_system {
StringRefNull essentials_directory_path() StringRefNull essentials_directory_path()
{ {
static std::string path = []() { static std::string path = []() {
const char *datafiles_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "assets"); const std::optional<std::string> datafiles_path = BKE_appdir_folder_id(BLENDER_DATAFILES,
if (datafiles_path == nullptr) { "assets");
return ""; return datafiles_path.value_or("");
}
return datafiles_path;
}(); }();
return path; return path;
} }

View File

@@ -23,8 +23,9 @@
static int blf_load_font_default(const char *filename, const bool unique) static int blf_load_font_default(const char *filename, const bool unique)
{ {
const char *dir = BKE_appdir_folder_id(BLENDER_DATAFILES, BLF_DATAFILES_FONTS_DIR); const std::optional<std::string> dir = BKE_appdir_folder_id(BLENDER_DATAFILES,
if (dir == nullptr) { BLF_DATAFILES_FONTS_DIR);
if (!dir.has_value()) {
fprintf(stderr, fprintf(stderr,
"%s: 'fonts' data path not found for '%s', will not be able to display text\n", "%s: 'fonts' data path not found for '%s', will not be able to display text\n",
__func__, __func__,
@@ -33,7 +34,7 @@ static int blf_load_font_default(const char *filename, const bool unique)
} }
char filepath[FILE_MAX]; char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), dir, filename); BLI_path_join(filepath, sizeof(filepath), dir->c_str(), filename);
return (unique) ? BLF_load_unique(filepath) : BLF_load(filepath); return (unique) ? BLF_load_unique(filepath) : BLF_load(filepath);
} }
@@ -55,18 +56,15 @@ int BLF_load_mono_default(const bool unique)
static void blf_load_datafiles_dir() static void blf_load_datafiles_dir()
{ {
const char *datafiles_fonts_dir = BLF_DATAFILES_FONTS_DIR SEP_STR; const char *datafiles_fonts_dir = BLF_DATAFILES_FONTS_DIR SEP_STR;
const char *path = BKE_appdir_folder_id(BLENDER_DATAFILES, datafiles_fonts_dir); const std::optional<std::string> path = BKE_appdir_folder_id(BLENDER_DATAFILES,
if (UNLIKELY(!path)) { datafiles_fonts_dir);
if (!path.has_value()) {
fprintf(stderr, "Font data directory \"%s\" could not be detected!\n", datafiles_fonts_dir); fprintf(stderr, "Font data directory \"%s\" could not be detected!\n", datafiles_fonts_dir);
return; return;
} }
if (UNLIKELY(!BLI_exists(path))) {
fprintf(stderr, "Font data directory \"%s\" does not exist!\n", path);
return;
}
direntry *file_list; direntry *file_list;
uint file_list_num = BLI_filelist_dir_contents(path, &file_list); uint file_list_num = BLI_filelist_dir_contents(path->c_str(), &file_list);
for (int i = 0; i < file_list_num; i++) { for (int i = 0; i < file_list_num; i++) {
if (S_ISDIR(file_list[i].s.st_mode)) { if (S_ISDIR(file_list[i].s.st_mode)) {
continue; continue;

View File

@@ -12,6 +12,9 @@
#include <stddef.h> #include <stddef.h>
#include <optional>
#include <string>
#include "BLI_compiler_attrs.h" #include "BLI_compiler_attrs.h"
struct ListBase; struct ListBase;
@@ -76,25 +79,26 @@ bool BKE_appdir_folder_id_ex(int folder_id,
const char *subfolder, const char *subfolder,
char *path, char *path,
size_t path_maxncpy); size_t path_maxncpy);
const char *BKE_appdir_folder_id(int folder_id, const char *subfolder) ATTR_WARN_UNUSED_RESULT; std::optional<std::string> BKE_appdir_folder_id(int folder_id,
const char *subfolder) ATTR_WARN_UNUSED_RESULT;
/** /**
* Returns the path to a folder in the user area, creating it if it doesn't exist. * Returns the path to a folder in the user area, creating it if it doesn't exist.
*/ */
const char *BKE_appdir_folder_id_create(int folder_id, std::optional<std::string> BKE_appdir_folder_id_create(int folder_id, const char *subfolder)
const char *subfolder) ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
/** /**
* Returns the path to a folder in the user area without checking that it actually exists first. * Returns the path to a folder in the user area without checking that it actually exists first.
*/ */
const char *BKE_appdir_folder_id_user_notest(int folder_id, std::optional<std::string> BKE_appdir_folder_id_user_notest(int folder_id, const char *subfolder)
const char *subfolder) ATTR_WARN_UNUSED_RESULT; ATTR_WARN_UNUSED_RESULT;
/** /**
* Returns the path of the top-level version-specific local, user or system directory. * Returns the path of the top-level version-specific local, user or system directory.
* If check_is_dir, then the result will be NULL if the directory doesn't exist. * If check_is_dir, then the result will be NULL if the directory doesn't exist.
*/ */
const char *BKE_appdir_resource_path_id_with_version(int folder_id, std::optional<std::string> BKE_appdir_resource_path_id_with_version(int folder_id,
bool check_is_dir, bool check_is_dir,
int version); int version);
const char *BKE_appdir_resource_path_id(int folder_id, bool check_is_dir); std::optional<std::string> BKE_appdir_resource_path_id(int folder_id, bool check_is_dir);
/** /**
* Check if this is an install with user files kept together * Check if this is an install with user files kept together

View File

@@ -685,19 +685,20 @@ bool BKE_appdir_folder_id_ex(const int folder_id,
return true; return true;
} }
const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder) std::optional<std::string> BKE_appdir_folder_id(const int folder_id, const char *subfolder)
{ {
static char path[FILE_MAX] = ""; char path[FILE_MAX] = "";
if (BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path))) { if (BKE_appdir_folder_id_ex(folder_id, subfolder, path, sizeof(path))) {
return path; return path;
} }
return nullptr; return std::nullopt;
} }
const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder) std::optional<std::string> BKE_appdir_folder_id_user_notest(const int folder_id,
const char *subfolder)
{ {
const int version = BLENDER_VERSION; const int version = BLENDER_VERSION;
static char path[FILE_MAX] = ""; char path[FILE_MAX] = "";
const bool check_is_dir = false; const bool check_is_dir = false;
switch (folder_id) { switch (folder_id) {
@@ -739,15 +740,13 @@ const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *su
} }
if ('\0' == path[0]) { if ('\0' == path[0]) {
return nullptr; return std::nullopt;
} }
return path; return path;
} }
const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfolder) std::optional<std::string> BKE_appdir_folder_id_create(const int folder_id, const char *subfolder)
{ {
const char *path;
/* Only for user folders. */ /* Only for user folders. */
if (!ELEM(folder_id, if (!ELEM(folder_id,
BLENDER_USER_DATAFILES, BLENDER_USER_DATAFILES,
@@ -756,26 +755,26 @@ const char *BKE_appdir_folder_id_create(const int folder_id, const char *subfold
BLENDER_USER_AUTOSAVE)) BLENDER_USER_AUTOSAVE))
{ {
BLI_assert_unreachable(); BLI_assert_unreachable();
return nullptr; return std::nullopt;
} }
path = BKE_appdir_folder_id(folder_id, subfolder); std::optional<std::string> path = BKE_appdir_folder_id(folder_id, subfolder);
if (!path) { if (!path.has_value()) {
path = BKE_appdir_folder_id_user_notest(folder_id, subfolder); path = BKE_appdir_folder_id_user_notest(folder_id, subfolder);
if (path) { if (path.has_value()) {
BLI_dir_create_recursive(path); BLI_dir_create_recursive(path->c_str());
} }
} }
return path; return path;
} }
const char *BKE_appdir_resource_path_id_with_version(const int folder_id, std::optional<std::string> BKE_appdir_resource_path_id_with_version(const int folder_id,
const bool check_is_dir, const bool check_is_dir,
const int version) const int version)
{ {
static char path[FILE_MAX] = ""; char path[FILE_MAX] = "";
bool ok; bool ok;
switch (folder_id) { switch (folder_id) {
case BLENDER_RESOURCE_PATH_USER: case BLENDER_RESOURCE_PATH_USER:
@@ -793,10 +792,14 @@ const char *BKE_appdir_resource_path_id_with_version(const int folder_id,
BLI_assert_msg(0, "incorrect ID"); BLI_assert_msg(0, "incorrect ID");
break; break;
} }
return ok ? path : nullptr; if (!ok) {
return std::nullopt;
}
return path;
} }
const char *BKE_appdir_resource_path_id(const int folder_id, const bool check_is_dir) std::optional<std::string> BKE_appdir_resource_path_id(const int folder_id,
const bool check_is_dir)
{ {
return BKE_appdir_resource_path_id_with_version(folder_id, check_is_dir, BLENDER_VERSION); return BKE_appdir_resource_path_id_with_version(folder_id, check_is_dir, BLENDER_VERSION);
} }
@@ -964,11 +967,13 @@ bool BKE_appdir_program_python_search(char *program_filepath,
SNPRINTF(python_version, "%s%d.%d", basename, version_major, version_minor); SNPRINTF(python_version, "%s%d.%d", basename, version_major, version_minor);
{ {
const char *python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, "bin"); const std::optional<std::string> python_bin_dir = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON,
if (python_bin_dir) { "bin");
if (python_bin_dir.has_value()) {
for (int i = 0; i < ARRAY_SIZE(python_names); i++) { for (int i = 0; i < ARRAY_SIZE(python_names); i++) {
BLI_path_join(program_filepath, program_filepath_maxncpy, python_bin_dir, python_names[i]); BLI_path_join(
program_filepath, program_filepath_maxncpy, python_bin_dir->c_str(), python_names[i]);
if ( if (
#ifdef _WIN32 #ifdef _WIN32

View File

@@ -1271,13 +1271,13 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *
bool BKE_blendfile_userdef_write_all(ReportList *reports) bool BKE_blendfile_userdef_write_all(ReportList *reports)
{ {
char filepath[FILE_MAX]; char filepath[FILE_MAX];
const char *cfgdir; std::optional<std::string> cfgdir;
bool ok = true; bool ok = true;
const bool use_template_userpref = BKE_appdir_app_template_has_userpref(U.app_template); const bool use_template_userpref = BKE_appdir_app_template_has_userpref(U.app_template);
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr))) { if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr))) {
bool ok_write; bool ok_write;
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_USERPREF_FILE);
printf("Writing userprefs: \"%s\" ", filepath); printf("Writing userprefs: \"%s\" ", filepath);
if (use_template_userpref) { if (use_template_userpref) {
@@ -1304,7 +1304,7 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
if (use_template_userpref) { if (use_template_userpref) {
if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) { if ((cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, U.app_template))) {
/* Also save app-template preferences. */ /* Also save app-template preferences. */
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_USERPREF_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: \"%s\" ", filepath); printf("Writing userprefs app-template: \"%s\" ", filepath);
if (BKE_blendfile_userdef_write(filepath, reports) != 0) { if (BKE_blendfile_userdef_write(filepath, reports) != 0) {

View File

@@ -609,13 +609,13 @@ static void studiolight_add_files_from_datafolder(const int folder_id,
const char *subfolder, const char *subfolder,
int flag) int flag)
{ {
const char *folder = BKE_appdir_folder_id(folder_id, subfolder); const std::optional<std::string> folder = BKE_appdir_folder_id(folder_id, subfolder);
if (!folder) { if (!folder) {
return; return;
} }
direntry *dirs; direntry *dirs;
const uint dirs_num = BLI_filelist_dir_contents(folder, &dirs); const uint dirs_num = BLI_filelist_dir_contents(folder->c_str(), &dirs);
int i; int i;
for (i = 0; i < dirs_num; i++) { for (i = 0; i < dirs_num; i++) {
if (dirs[i].type & S_IFREG) { if (dirs[i].type & S_IFREG) {

View File

@@ -65,16 +65,18 @@ static void free_locales()
static void fill_locales() static void fill_locales()
{ {
const char *const languages_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale"); std::optional<std::string> languages_path = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale");
char languages[FILE_MAX]; char languages[FILE_MAX];
LinkNode *lines = nullptr, *line; LinkNode *lines = nullptr, *line = nullptr;
char *str; char *str;
int idx = 0; int idx = 0;
free_locales(); free_locales();
BLI_path_join(languages, FILE_MAX, languages_path, "languages"); if (languages_path.has_value()) {
line = lines = BLI_file_read_as_lines(languages); BLI_path_join(languages, FILE_MAX, languages_path->c_str(), "languages");
line = lines = BLI_file_read_as_lines(languages);
}
/* This whole "parsing" code is a bit weak, in that it expects strictly formatted input file... /* This whole "parsing" code is a bit weak, in that it expects strictly formatted input file...
* Should not be a problem, though, as this file is script-generated! */ * Should not be a problem, though, as this file is script-generated! */
@@ -181,7 +183,7 @@ EnumPropertyItem *BLT_lang_RNA_enum_properties()
void BLT_lang_init() void BLT_lang_init()
{ {
#ifdef WITH_INTERNATIONAL #ifdef WITH_INTERNATIONAL
const char *const messagepath = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale"); const std::optional<std::string> messagepath = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale");
#endif #endif
/* Make sure LANG is correct and wouldn't cause #std::runtime_error. */ /* Make sure LANG is correct and wouldn't cause #std::runtime_error. */
@@ -212,8 +214,8 @@ void BLT_lang_init()
#endif #endif
#ifdef WITH_INTERNATIONAL #ifdef WITH_INTERNATIONAL
if (messagepath) { if (messagepath.has_value()) {
bl_locale_init(messagepath, TEXT_DOMAIN_NAME); bl_locale_init(messagepath->c_str(), TEXT_DOMAIN_NAME);
fill_locales(); fill_locales();
} }
else { else {

View File

@@ -950,11 +950,11 @@ static void init_internal_icons()
{ {
# if 0 /* temp disabled */ # if 0 /* temp disabled */
if ((btheme != nullptr) && btheme->tui.iconfile[0]) { if ((btheme != nullptr) && btheme->tui.iconfile[0]) {
char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); std::optional<std::string> icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
char iconfilestr[FILE_MAX]; char iconfilestr[FILE_MAX];
if (icondir) { if (icondir.has_value()) {
BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, btheme->tui.iconfile); BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir->c_str(), btheme->tui.iconfile);
/* if the image is missing bbuf will just be nullptr */ /* if the image is missing bbuf will just be nullptr */
bbuf = IMB_loadiffname(iconfilestr, IB_rect, nullptr); bbuf = IMB_loadiffname(iconfilestr, IB_rect, nullptr);
@@ -1054,14 +1054,14 @@ static void init_internal_icons()
static void init_iconfile_list(ListBase *list) static void init_iconfile_list(ListBase *list)
{ {
BLI_listbase_clear(list); BLI_listbase_clear(list);
const char *icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons"); const std::optional<std::string> icondir = BKE_appdir_folder_id(BLENDER_DATAFILES, "icons");
if (icondir == nullptr) { if (!icondir.has_value()) {
return; return;
} }
direntry *dir; direntry *dir;
const int totfile = BLI_filelist_dir_contents(icondir, &dir); const int totfile = BLI_filelist_dir_contents(icondir->c_str(), &dir);
int index = 1; int index = 1;
for (int i = 0; i < totfile; i++) { for (int i = 0; i < totfile; i++) {
@@ -1078,7 +1078,7 @@ static void init_iconfile_list(ListBase *list)
/* check to see if the image is the right size, continue if not */ /* check to see if the image is the right size, continue if not */
/* copying strings here should go ok, assuming that we never get back /* copying strings here should go ok, assuming that we never get back
* a complete path to file longer than 256 chars */ * a complete path to file longer than 256 chars */
BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir, filename); BLI_path_join(iconfilestr, sizeof(iconfilestr), icondir->c_str(), filename);
bbuf = IMB_loadiffname(iconfilestr, IB_rect); bbuf = IMB_loadiffname(iconfilestr, IB_rect);
if (bbuf) { if (bbuf) {

View File

@@ -52,12 +52,14 @@ const RecentCache *get_recent_cache_or_null()
static std::optional<std::string> get_recent_searches_file_path() static std::optional<std::string> get_recent_searches_file_path()
{ {
const char *user_config_dir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> user_config_dir = BKE_appdir_folder_id_create(
if (!user_config_dir) { BLENDER_USER_CONFIG, nullptr);
if (!user_config_dir.has_value()) {
return std::nullopt; return std::nullopt;
} }
char filepath[FILE_MAX]; char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), user_config_dir, BLENDER_RECENT_SEARCHES_FILE); BLI_path_join(
filepath, sizeof(filepath), user_config_dir->c_str(), BLENDER_RECENT_SEARCHES_FILE);
return std::string(filepath); return std::string(filepath);
} }

View File

@@ -1332,10 +1332,11 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush)
/* Otherwise lets try to find it in other directories. */ /* Otherwise lets try to find it in other directories. */
if (!(brush->icon_imbuf)) { if (!(brush->icon_imbuf)) {
const char *brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES, "brushicons"); const std::optional<std::string> brushicons_dir = BKE_appdir_folder_id(BLENDER_DATAFILES,
"brushicons");
/* Expected to be found, but don't crash if it's not. */ /* Expected to be found, but don't crash if it's not. */
if (brushicons_dir) { if (brushicons_dir.has_value()) {
BLI_path_join(filepath, sizeof(filepath), brushicons_dir, brush->icon_filepath); BLI_path_join(filepath, sizeof(filepath), brushicons_dir->c_str(), brush->icon_filepath);
/* Use default color spaces. */ /* Use default color spaces. */
brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr); brush->icon_imbuf = IMB_loadiffname(filepath, flags, nullptr);

View File

@@ -405,11 +405,13 @@ static void WORKSPACE_OT_append_activate(wmOperatorType *ot)
static WorkspaceConfigFileData *workspace_config_file_read(const char *app_template) static WorkspaceConfigFileData *workspace_config_file_read(const char *app_template)
{ {
const char *cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, app_template); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG,
app_template);
char startup_file_path[FILE_MAX] = {0}; char startup_file_path[FILE_MAX] = {0};
if (cfgdir) { if (cfgdir.has_value()) {
BLI_path_join(startup_file_path, sizeof(startup_file_path), cfgdir, BLENDER_STARTUP_FILE); BLI_path_join(
startup_file_path, sizeof(startup_file_path), cfgdir->c_str(), BLENDER_STARTUP_FILE);
} }
bool has_path = BLI_exists(startup_file_path); bool has_path = BLI_exists(startup_file_path);

View File

@@ -382,15 +382,16 @@ static bool fsmenu_write_file_and_refresh_or_report_error(FSMenu *fsmenu,
{ {
/* NOTE: use warning instead of error here, because the bookmark operation may be part of /* NOTE: use warning instead of error here, because the bookmark operation may be part of
* other actions which should not cause the operator to fail entirely. */ * other actions which should not cause the operator to fail entirely. */
const char *cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG,
if (UNLIKELY(!cfgdir)) { nullptr);
if (!cfgdir.has_value()) {
BKE_report(reports, RPT_ERROR, "Unable to create configuration directory to write bookmarks"); BKE_report(reports, RPT_ERROR, "Unable to create configuration directory to write bookmarks");
return false; return false;
} }
char filepath[FILE_MAX]; char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_BOOKMARK_FILE);
if (UNLIKELY(!fsmenu_write_file(fsmenu, filepath))) { if (!fsmenu_write_file(fsmenu, filepath)) {
BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath); BKE_reportf(reports, RPT_ERROR, "Unable to open or write bookmark file \"%s\"", filepath);
return false; return false;
} }

View File

@@ -136,11 +136,13 @@ void ED_fsmenu_entry_set_path(FSMenuEntry *fsentry, const char *path)
fsentry->path = (path && path[0]) ? BLI_strdup(path) : nullptr; fsentry->path = (path && path[0]) ? BLI_strdup(path) : nullptr;
BLI_path_join(tmp_name, const std::optional<std::string> user_config_dir = BKE_appdir_folder_id_create(
sizeof(tmp_name), BLENDER_USER_CONFIG, nullptr);
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr),
BLENDER_BOOKMARK_FILE); if (user_config_dir.has_value()) {
fsmenu_write_file(ED_fsmenu_get(), tmp_name); BLI_path_join(tmp_name, sizeof(tmp_name), user_config_dir->c_str(), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
} }
} }
@@ -200,11 +202,13 @@ void ED_fsmenu_entry_set_name(FSMenuEntry *fsentry, const char *name)
STRNCPY(fsentry->name, name); STRNCPY(fsentry->name, name);
} }
BLI_path_join(tmp_name, const std::optional<std::string> user_config_dir = BKE_appdir_folder_id_create(
sizeof(tmp_name), BLENDER_USER_CONFIG, nullptr);
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr),
BLENDER_BOOKMARK_FILE); if (user_config_dir.has_value()) {
fsmenu_write_file(ED_fsmenu_get(), tmp_name); BLI_path_join(tmp_name, sizeof(tmp_name), user_config_dir->c_str(), BLENDER_BOOKMARK_FILE);
fsmenu_write_file(ED_fsmenu_get(), tmp_name);
}
} }
} }

View File

@@ -1023,15 +1023,15 @@ void ED_file_exit()
void ED_file_read_bookmarks() void ED_file_read_bookmarks()
{ {
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
fsmenu_free(); fsmenu_free();
fsmenu_read_system(ED_fsmenu_get(), true); fsmenu_read_system(ED_fsmenu_get(), true);
if (cfgdir) { if (cfgdir.has_value()) {
char filepath[FILE_MAX]; char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_BOOKMARK_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_BOOKMARK_FILE);
fsmenu_read_bookmarks(ED_fsmenu_get(), filepath); fsmenu_read_bookmarks(ED_fsmenu_get(), filepath);
} }
} }

View File

@@ -23,7 +23,8 @@ Path::Path()
{ {
// get the root directory // get the root directory
// soc // soc
setRootDir(BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, nullptr)); const std::optional<std::string> path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, nullptr);
setRootDir(path.value_or(BKE_appdir_program_dir()));
_pInstance = this; _pInstance = this;
} }

View File

@@ -540,10 +540,11 @@ PyObject *Freestyle_Init()
PyDict_SetItemString(PySys_GetObject("modules"), module_definition.m_name, module); PyDict_SetItemString(PySys_GetObject("modules"), module_definition.m_name, module);
// update 'sys.path' for Freestyle Python API modules // update 'sys.path' for Freestyle Python API modules
const char *const path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "freestyle"); const std::optional<std::string> path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS,
if (path) { "freestyle");
if (path.has_value()) {
char modpath[FILE_MAX]; char modpath[FILE_MAX];
BLI_path_join(modpath, sizeof(modpath), path, "modules"); BLI_path_join(modpath, sizeof(modpath), path->c_str(), "modules");
PyObject *sys_path = PySys_GetObject("path"); /* borrow */ PyObject *sys_path = PySys_GetObject("path"); /* borrow */
PyObject *py_modpath = PyC_UnicodeFromBytes(modpath); PyObject *py_modpath = PyC_UnicodeFromBytes(modpath);
PyList_Append(sys_path, py_modpath); PyList_Append(sys_path, py_modpath);

View File

@@ -653,7 +653,6 @@ static void colormanage_free_config()
void colormanagement_init() void colormanagement_init()
{ {
const char *ocio_env; const char *ocio_env;
const char *configdir;
char configfile[FILE_MAX]; char configfile[FILE_MAX];
OCIO_ConstConfigRcPtr *config = nullptr; OCIO_ConstConfigRcPtr *config = nullptr;
@@ -669,10 +668,11 @@ void colormanagement_init()
} }
if (config == nullptr) { if (config == nullptr) {
configdir = BKE_appdir_folder_id(BLENDER_DATAFILES, "colormanagement"); const std::optional<std::string> configdir = BKE_appdir_folder_id(BLENDER_DATAFILES,
"colormanagement");
if (configdir) { if (configdir.has_value()) {
BLI_path_join(configfile, sizeof(configfile), configdir, BCM_CONFIG_FILE); BLI_path_join(configfile, sizeof(configfile), configdir->c_str(), BCM_CONFIG_FILE);
config = OCIO_configCreateFromFile(configfile); config = OCIO_configCreateFromFile(configfile);
} }

View File

@@ -74,14 +74,13 @@ static PyObject *bpy_script_paths(PyObject * /*self*/)
{ {
PyObject *ret = PyTuple_New(2); PyObject *ret = PyTuple_New(2);
PyObject *item; PyObject *item;
const char *path;
path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, nullptr); std::optional<std::string> path = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, nullptr);
item = PyC_UnicodeFromBytes(path ? path : ""); item = PyC_UnicodeFromBytes(path.has_value() ? path->c_str() : "");
BLI_assert(item != nullptr); BLI_assert(item != nullptr);
PyTuple_SET_ITEM(ret, 0, item); PyTuple_SET_ITEM(ret, 0, item);
path = BKE_appdir_folder_id(BLENDER_USER_SCRIPTS, nullptr); path = BKE_appdir_folder_id(BLENDER_USER_SCRIPTS, nullptr);
item = PyC_UnicodeFromBytes(path ? path : ""); item = PyC_UnicodeFromBytes(path.has_value() ? path->c_str() : "");
BLI_assert(item != nullptr); BLI_assert(item != nullptr);
PyTuple_SET_ITEM(ret, 1, item); PyTuple_SET_ITEM(ret, 1, item);
@@ -249,10 +248,11 @@ static PyObject *bpy_user_resource(PyObject * /*self*/, PyObject *args, PyObject
/* same logic as BKE_appdir_folder_id_create(), /* same logic as BKE_appdir_folder_id_create(),
* but best leave it up to the script author to create */ * but best leave it up to the script author to create */
const char *path = BKE_appdir_folder_id_user_notest(type.value_found, subdir_data.value); const std::optional<std::string> path = BKE_appdir_folder_id_user_notest(type.value_found,
subdir_data.value);
Py_XDECREF(subdir_data.value_coerce); Py_XDECREF(subdir_data.value_coerce);
return PyC_UnicodeFromBytes(path ? path : ""); return PyC_UnicodeFromBytes(path.has_value() ? path->c_str() : "");
} }
PyDoc_STRVAR(bpy_system_resource_doc, PyDoc_STRVAR(bpy_system_resource_doc,
@@ -297,10 +297,10 @@ static PyObject *bpy_system_resource(PyObject * /*self*/, PyObject *args, PyObje
return nullptr; return nullptr;
} }
const char *path = BKE_appdir_folder_id(type.value_found, subdir_data.value); std::optional<std::string> path = BKE_appdir_folder_id(type.value_found, subdir_data.value);
Py_XDECREF(subdir_data.value_coerce); Py_XDECREF(subdir_data.value_coerce);
return PyC_UnicodeFromBytes(path ? path : ""); return PyC_UnicodeFromBytes(path.has_value() ? path->c_str() : "");
} }
PyDoc_STRVAR( PyDoc_STRVAR(
@@ -328,7 +328,6 @@ static PyObject *bpy_resource_path(PyObject * /*self*/, PyObject *args, PyObject
PyC_StringEnum type = {type_items}; PyC_StringEnum type = {type_items};
int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100; int major = BLENDER_VERSION / 100, minor = BLENDER_VERSION % 100;
const char *path;
static const char *_keywords[] = {"type", "major", "minor", nullptr}; static const char *_keywords[] = {"type", "major", "minor", nullptr};
static _PyArg_Parser _parser = { static _PyArg_Parser _parser = {
@@ -347,9 +346,10 @@ static PyObject *bpy_resource_path(PyObject * /*self*/, PyObject *args, PyObject
return nullptr; return nullptr;
} }
path = BKE_appdir_resource_path_id_with_version(type.value_found, false, (major * 100) + minor); const std::optional<std::string> path = BKE_appdir_resource_path_id_with_version(
type.value_found, false, (major * 100) + minor);
return PyC_UnicodeFromBytes(path ? path : ""); return PyC_UnicodeFromBytes(path.has_value() ? path->c_str() : "");
} }
/* This is only exposed for tests, see: `tests/python/bl_pyapi_bpy_driver_secure_eval.py`. */ /* This is only exposed for tests, see: `tests/python/bl_pyapi_bpy_driver_secure_eval.py`. */
@@ -643,11 +643,12 @@ void BPy_init_modules(bContext *C)
PyObject *mod; PyObject *mod;
/* Needs to be first since this dir is needed for future modules */ /* Needs to be first since this dir is needed for future modules */
const char *const modpath = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS, "modules"); const std::optional<std::string> modpath = BKE_appdir_folder_id(BLENDER_SYSTEM_SCRIPTS,
if (modpath) { "modules");
if (modpath.has_value()) {
// printf("bpy: found module path '%s'.\n", modpath); // printf("bpy: found module path '%s'.\n", modpath);
PyObject *sys_path = PySys_GetObject("path"); /* borrow */ PyObject *sys_path = PySys_GetObject("path"); /* borrow */
PyObject *py_modpath = PyC_UnicodeFromBytes(modpath); PyObject *py_modpath = PyC_UnicodeFromBytes(modpath->c_str());
PyList_Insert(sys_path, 0, py_modpath); /* add first */ PyList_Insert(sys_path, 0, py_modpath); /* add first */
Py_DECREF(py_modpath); Py_DECREF(py_modpath);
} }

View File

@@ -434,21 +434,22 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
/* Allow to use our own included Python. `py_path_bundle` may be nullptr. */ /* Allow to use our own included Python. `py_path_bundle` may be nullptr. */
{ {
const char *py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, nullptr); const std::optional<std::string> py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON,
if (py_path_bundle != nullptr) { nullptr);
if (py_path_bundle.has_value()) {
# ifdef __APPLE__ # ifdef __APPLE__
/* Mac-OS allows file/directory names to contain `:` character /* Mac-OS allows file/directory names to contain `:` character
* (represented as `/` in the Finder) but current Python lib (as of release 3.1.1) * (represented as `/` in the Finder) but current Python lib (as of release 3.1.1)
* doesn't handle these correctly. */ * doesn't handle these correctly. */
if (strchr(py_path_bundle, ':')) { if (strchr(py_path_bundle->c_str(), ':')) {
fprintf(stderr, fprintf(stderr,
"Warning! Blender application is located in a path containing ':' or '/' chars\n" "Warning! Blender application is located in a path containing ':' or '/' chars\n"
"This may make Python import function fail\n"); "This may make Python import function fail\n");
} }
# endif /* __APPLE__ */ # endif /* __APPLE__ */
status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle); status = PyConfig_SetBytesString(&config, &config.home, py_path_bundle->c_str());
pystatus_exit_on_error(status); pystatus_exit_on_error(status);
# ifdef PYTHON_SSL_CERT_FILE # ifdef PYTHON_SSL_CERT_FILE
@@ -458,7 +459,7 @@ void BPY_python_start(bContext *C, int argc, const char **argv)
const char *ssl_cert_file_suffix = PYTHON_SSL_CERT_FILE; const char *ssl_cert_file_suffix = PYTHON_SSL_CERT_FILE;
char ssl_cert_file[FILE_MAX]; char ssl_cert_file[FILE_MAX];
BLI_path_join( BLI_path_join(
ssl_cert_file, sizeof(ssl_cert_file), py_path_bundle, ssl_cert_file_suffix); ssl_cert_file, sizeof(ssl_cert_file), py_path_bundle->c_str(), ssl_cert_file_suffix);
BLI_setenv(ssl_cert_file_env, ssl_cert_file); BLI_setenv(ssl_cert_file_env, ssl_cert_file);
} }
# endif /* PYTHON_SSL_CERT_FILE */ # endif /* PYTHON_SSL_CERT_FILE */

View File

@@ -1279,13 +1279,15 @@ void wm_homefile_read_ex(bContext *C,
app_template_system[0] = '\0'; app_template_system[0] = '\0';
app_template_config[0] = '\0'; app_template_config[0] = '\0';
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
if (!use_factory_settings) { if (!use_factory_settings) {
if (cfgdir) { if (cfgdir.has_value()) {
BLI_path_join(filepath_startup, sizeof(filepath_startup), cfgdir, BLENDER_STARTUP_FILE); BLI_path_join(
filepath_startup, sizeof(filepath_startup), cfgdir->c_str(), BLENDER_STARTUP_FILE);
filepath_startup_is_factory = false; filepath_startup_is_factory = false;
if (use_userdef) { if (use_userdef) {
BLI_path_join(filepath_userdef, sizeof(filepath_startup), cfgdir, BLENDER_USERPREF_FILE); BLI_path_join(
filepath_userdef, sizeof(filepath_startup), cfgdir->c_str(), BLENDER_USERPREF_FILE);
} }
} }
else { else {
@@ -1328,8 +1330,9 @@ void wm_homefile_read_ex(bContext *C,
/* note that the path is being set even when 'use_factory_settings == true' /* note that the path is being set even when 'use_factory_settings == true'
* this is done so we can load a templates factory-settings */ * this is done so we can load a templates factory-settings */
if (!use_factory_settings) { if (!use_factory_settings && cfgdir.has_value()) {
BLI_path_join(app_template_config, sizeof(app_template_config), cfgdir, app_template); BLI_path_join(
app_template_config, sizeof(app_template_config), cfgdir->c_str(), app_template);
BLI_path_join( BLI_path_join(
filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE); filepath_startup, sizeof(filepath_startup), app_template_config, BLENDER_STARTUP_FILE);
filepath_startup_is_factory = false; filepath_startup_is_factory = false;
@@ -1534,8 +1537,8 @@ void wm_homefile_read_post(bContext *C, const wmFileReadPost_Params *params_file
void wm_history_file_read() void wm_history_file_read()
{ {
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
if (!cfgdir) { if (!cfgdir.has_value()) {
return; return;
} }
@@ -1543,7 +1546,7 @@ void wm_history_file_read()
LinkNode *l; LinkNode *l;
int num; int num;
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_HISTORY_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_HISTORY_FILE);
LinkNode *lines = BLI_file_read_as_lines(filepath); LinkNode *lines = BLI_file_read_as_lines(filepath);
@@ -1597,17 +1600,17 @@ static RecentFile *wm_file_history_find(const char *filepath)
*/ */
static void wm_history_file_write() static void wm_history_file_write()
{ {
const char *user_config_dir;
char filepath[FILE_MAX]; char filepath[FILE_MAX];
FILE *fp; FILE *fp;
/* will be nullptr in background mode */ /* will be nullptr in background mode */
user_config_dir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> user_config_dir = BKE_appdir_folder_id_create(
if (!user_config_dir) { BLENDER_USER_CONFIG, nullptr);
if (!user_config_dir.has_value()) {
return; return;
} }
BLI_path_join(filepath, sizeof(filepath), user_config_dir, BLENDER_HISTORY_FILE); BLI_path_join(filepath, sizeof(filepath), user_config_dir->c_str(), BLENDER_HISTORY_FILE);
fp = BLI_fopen(filepath, "w"); fp = BLI_fopen(filepath, "w");
if (fp) { if (fp) {
@@ -2093,10 +2096,11 @@ static void wm_autosave_location(char filepath[FILE_MAX])
* If this is still the case on WIN32 - other features such as copy-paste will also fail. * If this is still the case on WIN32 - other features such as copy-paste will also fail.
* We could support #BLENDER_USER_AUTOSAVE on all platforms or remove it entirely. */ * We could support #BLENDER_USER_AUTOSAVE on all platforms or remove it entirely. */
#ifdef WIN32 #ifdef WIN32
std::optional<std::string> savedir;
if (!BLI_exists(tempdir_base)) { if (!BLI_exists(tempdir_base)) {
const char *savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, nullptr); savedir = BKE_appdir_folder_id_create(BLENDER_USER_AUTOSAVE, nullptr);
if (savedir) { if (savedir.has_value()) {
tempdir_base = savedir; tempdir_base = savedir->c_str();
} }
} }
#endif #endif
@@ -2277,8 +2281,9 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
int fileflags; int fileflags;
const char *app_template = U.app_template[0] ? U.app_template : nullptr; const char *app_template = U.app_template[0] ? U.app_template : nullptr;
const char *const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template); const std::optional<std::string> cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG,
if (cfgdir == nullptr) { app_template);
if (!cfgdir.has_value()) {
BKE_report(op->reports, RPT_ERROR, "Unable to create user config path"); BKE_report(op->reports, RPT_ERROR, "Unable to create user config path");
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
@@ -2296,7 +2301,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
/* update keymaps in user preferences */ /* update keymaps in user preferences */
WM_keyconfig_update(wm); WM_keyconfig_update(wm);
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_STARTUP_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_STARTUP_FILE);
printf("Writing homefile: \"%s\" ", filepath); printf("Writing homefile: \"%s\" ", filepath);

View File

@@ -375,10 +375,10 @@ static bool wm_init_splash_show_on_startup_check()
else { else {
/* A less common case, if there is no user preferences, show the splash screen /* A less common case, if there is no user preferences, show the splash screen
* so the user has the opportunity to restore settings from a previous version. */ * so the user has the opportunity to restore settings from a previous version. */
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
if (cfgdir) { if (cfgdir.has_value()) {
char userpref[FILE_MAX]; char userpref[FILE_MAX];
BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE); BLI_path_join(userpref, sizeof(userpref), cfgdir->c_str(), BLENDER_USERPREF_FILE);
if (!BLI_exists(userpref)) { if (!BLI_exists(userpref)) {
use_splash = true; use_splash = true;
} }

View File

@@ -36,14 +36,14 @@ static bool wm_platform_support_check_approval(const char *platform_support_key,
if (G.factory_startup) { if (G.factory_startup) {
return false; return false;
} }
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
if (!cfgdir) { if (!cfgdir.has_value()) {
return false; return false;
} }
bool result = false; bool result = false;
char filepath[FILE_MAX]; char filepath[FILE_MAX];
BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_PLATFORM_SUPPORT_FILE); BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_PLATFORM_SUPPORT_FILE);
LinkNode *lines = BLI_file_read_as_lines(filepath); LinkNode *lines = BLI_file_read_as_lines(filepath);
for (LinkNode *line_node = lines; line_node; line_node = line_node->next) { for (LinkNode *line_node = lines; line_node; line_node = line_node->next) {
const char *line = static_cast<char *>(line_node->link); const char *line = static_cast<char *>(line_node->link);

View File

@@ -216,10 +216,10 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *region, void * /*ar
MenuType *mt; MenuType *mt;
char userpref[FILE_MAX]; char userpref[FILE_MAX];
const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr); const std::optional<std::string> cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, nullptr);
if (cfgdir) { if (cfgdir.has_value()) {
BLI_path_join(userpref, sizeof(userpref), cfgdir, BLENDER_USERPREF_FILE); BLI_path_join(userpref, sizeof(userpref), cfgdir->c_str(), BLENDER_USERPREF_FILE);
} }
/* Draw setup screen if no preferences have been saved yet. */ /* Draw setup screen if no preferences have been saved yet. */