higan-emu / higan

higan is a multi-system emulator focused on accuracy, preservation, and configurability.
Other
1.17k stars 111 forks source link

higan should interpret paths in paths.bml as relative to that file #43

Open Screwtapello opened 4 years ago

Screwtapello commented 4 years ago

Currently, when higan starts up, it looks for a paths.bml file beside the executable. If it exists, higan reads the path to the data and template directories from it. If they're absolute paths, that's fine, but if they're relative paths then higan uses them as-is... which means they're interpreted relative to whatever the current working directory happens to be.

Normally this is fine, because when you double-click an executable in Windows it sets the current working directory to the executable directory, but if you drag a ROM onto the executable, or if you launch it from the command-line for some reason, the current working directory can be set to something else, so higan might not be able to find the support files it needs.

Instead, higan should check whether the paths loaded from paths.bml are relative or absolute, and if they're relative, it should convert them to absolute paths by prefixing them with the directory containing paths.bml.

Hopefully nall's path-handling includes a way to detect relative paths and to join paths together, otherwise that functionality will need to be added.

Kawa-oneechan commented 4 years ago

It seems nall has the Path::program function to provide this information:

inline auto real(string_view name) -> string {
  string result;
  char path[PATH_MAX] = "";
  if(::realpath(name, path)) result = Location::path(string{path}.transform("\\", "/"));
  if(!result) return active();
  result.transform("\\", "/");
  if(!result.endsWith("/")) result.append("/");
  return result;
}

inline auto program() -> string {
  #if defined(PLATFORM_WINDOWS)
  wchar_t path[PATH_MAX] = L"";
  GetModuleFileName(nullptr, path, PATH_MAX);
  string result = (const char*)utf8_t(path);
  result.transform("\\", "/");
  return Path::real(result);
  #else
  Dl_info info;
  dladdr((void*)&program, &info);
  return Path::real(info.dli_fname);
  #endif
}

Unless I'm more affected than I thought, this would first figure out c:\emulators\higan\higan.exe, then have Path::real reduce that to just c:\emulators\higan\.

Screwtapello commented 4 years ago

The other part of the problem is detecting relative versus absolute paths. For instance, c:/foo is an absolute path on Windows but a relative path on POSIX, while /foo is an absolute path on POSIX but a relative path on Windows.

Kawa-oneechan commented 4 years ago
  1. Path::real returns absolute paths for relative inputs. If the output matches the input, the input was probably absolute to begin with.
  2. #if defined(PLATFORM_WINDOWS), you can detect relative paths yourself without option 1. Naively, you might check if the second character is a :.
Screwtapello commented 4 years ago

Naively, you might check if the second character is a :.

A counter-example: the relative path C:foo.

Kawa-oneechan commented 4 years ago

Then we shall be less naive and also check if the third character is \, and if the first is alphabetic.