35 const char* userprofile = std::getenv(
"USERPROFILE");
36 if (userprofile && *userprofile) {
37 return std::filesystem::path(userprofile);
41 const char* homedrive = std::getenv(
"HOMEDRIVE");
42 const char* homepath = std::getenv(
"HOMEPATH");
43 if (homedrive && homepath) {
44 return std::filesystem::path(std::string(homedrive) +
45 std::string(homepath));
50 auto temp = std::filesystem::temp_directory_path(ec);
54 return std::filesystem::path(
".");
55#elif defined(__EMSCRIPTEN__)
57 return std::filesystem::path(
"/home/web_user");
60 const char* home = std::getenv(
"HOME");
62 return std::filesystem::path(home);
66 struct passwd* pw = getpwuid(getuid());
67 if (pw && pw->pw_dir) {
68 return std::filesystem::path(pw->pw_dir);
73 auto cwd = std::filesystem::current_path(ec);
77 return std::filesystem::path(
".");
81 return std::filesystem::path(
".");
86 if (
const char* override_dir = std::getenv(
"YAZE_APP_DATA_DIR")) {
88 std::filesystem::path app_data(override_dir);
97#if defined(YAZE_IOS) || defined(YAZE_APPLE_MOBILE)
99 if (home.empty() || home ==
".") {
101 auto temp = std::filesystem::temp_directory_path(ec);
107 std::filesystem::path app_data =
108 home /
"Library" /
"Application Support" /
".yaze";
111 app_data = home /
"Documents" /
".yaze";
118#elif defined(__EMSCRIPTEN__)
130 std::filesystem::path app_data(
"/.yaze");
134 std::filesystem::path preferred;
135 if (!home.empty() && home !=
".") {
136 preferred = home /
".yaze";
139 std::vector<std::filesystem::path> legacy_paths;
140 auto add_legacy_path = [&](
const std::filesystem::path& path) {
144 if (std::find(legacy_paths.begin(), legacy_paths.end(), path) ==
145 legacy_paths.end()) {
146 legacy_paths.push_back(path);
151 wchar_t path[MAX_PATH];
152 if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_APPDATA, NULL, 0, path))) {
153 add_legacy_path(std::filesystem::path(path) /
"yaze");
155 if (
const char* appdata = std::getenv(
"APPDATA")) {
157 add_legacy_path(std::filesystem::path(appdata) /
"yaze");
160#elif defined(__APPLE__)
161 if (!home.empty() && home !=
".") {
162 add_legacy_path(home /
"Library" /
"Application Support" /
"yaze");
163 add_legacy_path(home /
"Library" /
"Application Support" /
"Yaze");
166 if (!home.empty() && home !=
".") {
167 add_legacy_path(home /
".config" /
"yaze");
171 auto try_migrate = [&](
const std::filesystem::path& legacy) -> absl::Status {
172 if (legacy.empty() || preferred.empty()) {
173 return absl::OkStatus();
176 return absl::OkStatus();
180 std::filesystem::rename(legacy, preferred, ec);
182 return absl::OkStatus();
185 std::filesystem::create_directories(preferred, ec);
187 return absl::InternalError(
188 absl::StrCat(
"Failed to create .yaze directory: ", ec.message()));
191 std::filesystem::copy(legacy, preferred,
192 std::filesystem::copy_options::recursive |
193 std::filesystem::copy_options::skip_existing,
196 return absl::InternalError(
197 absl::StrCat(
"Failed to migrate legacy data: ", ec.message()));
203 std::filesystem::remove_all(legacy, ec);
206 return absl::OkStatus();
209 if (!preferred.empty()) {
211 for (
const auto& legacy : legacy_paths) {
213 (void)try_migrate(legacy);
225 for (
const auto& legacy : legacy_paths) {
232 if (preferred.empty()) {
233 std::filesystem::path fallback = std::filesystem::current_path() /
".yaze";
241 return absl::InternalError(
"Failed to resolve app data directory");
261#if defined(YAZE_IOS) || defined(YAZE_APPLE_MOBILE)
263 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
266 docs_dir = home /
"Yaze";
274 wchar_t path[MAX_PATH];
275 if (SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, 0, path))) {
276 std::filesystem::path docs_dir = std::filesystem::path(path) /
"Yaze";
285 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
291#elif defined(__EMSCRIPTEN__)
293 std::filesystem::path docs_dir(
"/.yaze/projects");
298 std::filesystem::path docs_dir = home /
"Documents" /
"Yaze";
302 docs_dir = home /
"Yaze";
406 const std::string& relative_path) {
407 std::vector<std::filesystem::path> search_paths;
411#ifdef YAZE_ASSETS_PATH
413 search_paths.push_back(std::filesystem::path(YAZE_ASSETS_PATH) /
421 static std::filesystem::path cached_cwd;
422 static bool cwd_cached =
false;
426 cached_cwd = std::filesystem::current_path(ec);
430 if (!cached_cwd.empty()) {
432 search_paths.push_back(cached_cwd /
"assets" / relative_path);
439 static std::filesystem::path cached_exe_dir;
440 static bool exe_dir_cached =
false;
442 if (!exe_dir_cached) {
445 char exe_path[PATH_MAX];
446 uint32_t size =
sizeof(exe_path);
447 if (_NSGetExecutablePath(exe_path, &size) == 0) {
448 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
450#elif defined(__linux__)
451 char exe_path[PATH_MAX];
453 readlink(
"/proc/self/exe", exe_path,
sizeof(exe_path) - 1);
455 exe_path[len] =
'\0';
456 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
459 wchar_t exe_path[MAX_PATH];
460 if (GetModuleFileNameW(NULL, exe_path, MAX_PATH) != 0) {
461 cached_exe_dir = std::filesystem::path(exe_path).parent_path();
467 exe_dir_cached =
true;
470 if (!cached_exe_dir.empty()) {
472 search_paths.push_back(cached_exe_dir /
"assets" / relative_path);
474 search_paths.push_back(cached_exe_dir.parent_path() /
"assets" /
480 auto contents_dir = cached_exe_dir.parent_path();
481 auto bundle_dir = contents_dir.parent_path();
482 auto bundle_parent = bundle_dir.parent_path();
483 search_paths.push_back(contents_dir /
"Resources" /
"assets" /
485 search_paths.push_back(bundle_parent /
"assets" / relative_path);
493 if (!cached_cwd.empty()) {
495 auto parent = cached_cwd.parent_path();
496 if (!parent.empty() && parent != cached_cwd) {
497 search_paths.push_back(parent /
"assets" / relative_path);
498 auto grandparent = parent.parent_path();
499 if (!grandparent.empty() && grandparent != parent) {
500 search_paths.push_back(grandparent /
"assets" / relative_path);
509 static std::filesystem::path cached_home;
510 static bool home_cached =
false;
521 if (!cached_home.empty() && cached_home !=
".") {
523 search_paths.push_back(cached_home /
".yaze" /
"assets" /
533 search_paths.push_back(
534 std::filesystem::path(
"/usr/local/share/yaze/assets") /
536 search_paths.push_back(std::filesystem::path(
"/usr/share/yaze/assets") /
545 const size_t max_paths_to_check = 20;
548 for (
const auto& candidate : search_paths) {
549 if (++checked > max_paths_to_check) {
555 std::error_code exists_ec;
556 if (std::filesystem::exists(candidate, exists_ec) && !exists_ec) {
558 auto status = std::filesystem::status(candidate, exists_ec);
560 status.type() != std::filesystem::file_type::not_found) {
571 return absl::NotFoundError(
572 absl::StrCat(
"Asset not found: ", relative_path));
574 }
catch (
const std::exception& e) {
575 return absl::InternalError(
576 absl::StrCat(
"Exception while searching for asset: ", e.what()));
578 return absl::InternalError(
"Unknown exception while searching for asset");