|
18 | 18 |
|
19 | 19 | static char data_dir[MAX_PATH_LEN]; |
20 | 20 | static char write_dir[MAX_PATH_LEN]; |
| 21 | +static char program_dir[MAX_PATH_LEN]; |
21 | 22 |
|
22 | 23 | /* The extensions an episode's two group files carry. */ |
23 | 24 | static const char *const GROUP_EXTENSIONS[] = {"STN", "VOL"}; |
@@ -67,6 +68,40 @@ static bool group_path(char *dest, size_t size, const char *dir, int episode, |
67 | 68 | return path_join(dest, size, dir, leaf); |
68 | 69 | } |
69 | 70 |
|
| 71 | +/* |
| 72 | + * Work out where sibling executables are, from where SDL says the application's |
| 73 | + * files are. |
| 74 | + * |
| 75 | + * In a bundle those are two different places. SDL_GetBasePath() points at |
| 76 | + * Contents/Resources, because that is where an application's data belongs, but |
| 77 | + * the programs are in Contents/MacOS. Reading the first as though it were the |
| 78 | + * second is how the launcher came to look for the episodes among the artwork. |
| 79 | + */ |
| 80 | +static void resolve_program_dir(const char *base) |
| 81 | +{ |
| 82 | + static const char RESOURCES[] = "/Contents/Resources"; |
| 83 | + size_t base_length, suffix_length = sizeof RESOURCES - 1; |
| 84 | + |
| 85 | + if (!base || !path_copy(program_dir, sizeof program_dir, base)) { |
| 86 | + path_copy(program_dir, sizeof program_dir, "."); |
| 87 | + return; |
| 88 | + } |
| 89 | + |
| 90 | + base_length = SDL_strlen(program_dir); |
| 91 | + while (base_length > 1 && (program_dir[base_length - 1] == '/' || |
| 92 | + program_dir[base_length - 1] == '\\')) { |
| 93 | + program_dir[--base_length] = '\0'; |
| 94 | + } |
| 95 | + |
| 96 | + if (base_length > suffix_length && |
| 97 | + SDL_strcasecmp(program_dir + base_length - suffix_length, RESOURCES) == 0) |
| 98 | + { |
| 99 | + /* Swap the last component: Contents/Resources -> Contents/MacOS. */ |
| 100 | + program_dir[base_length - suffix_length] = '\0'; |
| 101 | + SDL_strlcat(program_dir, "/Contents/MacOS", sizeof program_dir); |
| 102 | + } |
| 103 | +} |
| 104 | + |
70 | 105 | static bool dir_has_any_episode(const char *dir) |
71 | 106 | { |
72 | 107 | int episode; |
@@ -178,6 +213,8 @@ bool paths_init(void) |
178 | 213 | const char *prefs; |
179 | 214 | int i, episode; |
180 | 215 |
|
| 216 | + resolve_program_dir(SDL_GetBasePath()); |
| 217 | + |
181 | 218 | /* Used in place when the data sits somewhere that takes the saves too. */ |
182 | 219 | for (i = 0; i < count; i++) { |
183 | 220 | if (dir_has_any_episode(shipped[i]) && dir_is_writable(shipped[i])) { |
@@ -228,6 +265,11 @@ const char *paths_write_dir(void) |
228 | 265 | return write_dir; |
229 | 266 | } |
230 | 267 |
|
| 268 | +const char *paths_program_dir(void) |
| 269 | +{ |
| 270 | + return program_dir; |
| 271 | +} |
| 272 | + |
231 | 273 | bool paths_import_episode(const char *chosen_file, int episode) |
232 | 274 | { |
233 | 275 | char folder[MAX_PATH_LEN]; |
|
0 commit comments