1 /* RetroArch - A frontend for libretro.
2 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
3 * Copyright (C) 2011-2017 - Daniel De Matteis
4 *
5 * RetroArch is free software: you can redistribute it and/or modify it under the terms
6 * of the GNU General Public License as published by the Free Software Found-
7 * ation, either version 3 of the License, or (at your option) any later version.
8 *
9 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 * PURPOSE. See the GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along with RetroArch.
14 * If not, see <http://www.gnu.org/licenses/>.
15 */
16
17 #include <stdint.h>
18 #include <boolean.h>
19 #include <stddef.h>
20 #include <string.h>
21
22 #include <file/config_file.h>
23 #include <file/file_path.h>
24 #include <lists/dir_list.h>
25 #include <retro_miscellaneous.h>
26 #include <string/stdstring.h>
27 #include <compat/strl.h>
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "frontend_driver.h"
34 #include "../defaults.h"
35 #include "../verbosity.h"
36 #include "../file_path_special.h"
37
38 struct defaults g_defaults;
39
40 /*We need to set libretro to the first entry in the cores
41 * directory so that it will be saved to the config file
42 */
find_first_libretro_core(char * first_file,size_t size_of_first_file,const char * dir,const char * ext)43 static void find_first_libretro_core(char *first_file,
44 size_t size_of_first_file, const char *dir,
45 const char * ext)
46 {
47 size_t i;
48 bool ret = false;
49 struct string_list *list = dir_list_new(dir, ext, false, true, false, false);
50
51 if (!list)
52 {
53 RARCH_ERR("Couldn't read directory."
54 " Cannot infer default libretro core.\n");
55 return;
56 }
57
58 RARCH_LOG("Searching for valid libretro implementation in: \"%s\".\n",
59 dir);
60
61 for (i = 0; i < list->size && !ret; i++)
62 {
63 char fname[PATH_MAX_LENGTH] = {0};
64 char salamander_name[PATH_MAX_LENGTH] = {0};
65 const char *libretro_elem = (const char*)list->elems[i].data;
66
67 RARCH_LOG("Checking library: \"%s\".\n", libretro_elem);
68
69 if (!libretro_elem)
70 continue;
71
72 fill_pathname_base(fname, libretro_elem, sizeof(fname));
73
74 if (!frontend_driver_get_salamander_basename(
75 salamander_name, sizeof(salamander_name)))
76 break;
77
78 if (!strncmp(fname, salamander_name, sizeof(fname)))
79 {
80 if (list->size == (i + 1))
81 {
82 RARCH_WARN("Entry is RetroArch Salamander itself, "
83 "but is last entry. No choice but to set it.\n");
84 strlcpy(first_file, fname, size_of_first_file);
85 }
86
87 continue;
88 }
89
90 strlcpy(first_file, fname, size_of_first_file);
91 RARCH_LOG("First found libretro core is: \"%s\".\n", first_file);
92 ret = true;
93 }
94
95 dir_list_free(list);
96 }
97
98 /* Last fallback - we'll need to start the first executable file
99 * we can find in the RetroArch cores directory.
100 */
find_and_set_first_file(char * s,size_t len,const char * ext)101 static void find_and_set_first_file(char *s, size_t len,
102 const char *ext)
103 {
104
105 char first_file[PATH_MAX_LENGTH] = {0};
106 find_first_libretro_core(first_file, sizeof(first_file),
107 g_defaults.dirs[DEFAULT_DIR_CORE], ext);
108
109 if (string_is_empty(first_file))
110 {
111 RARCH_ERR("Failed last fallback - RetroArch Salamander will exit.\n");
112 return;
113 }
114
115 fill_pathname_join(s, g_defaults.dirs[DEFAULT_DIR_CORE], first_file, len);
116 RARCH_LOG("libretro_path now set to: %s.\n", s);
117 }
118
salamander_init(char * s,size_t len)119 static void salamander_init(char *s, size_t len)
120 {
121 /* Normal executable loading path */
122 config_file_t *config = NULL;
123 const char *rarch_config_path = g_defaults.path_config;
124 bool config_valid = false;
125 char config_path[PATH_MAX_LENGTH];
126 char config_dir[PATH_MAX_LENGTH];
127
128 config_path[0] = '\0';
129 config_dir[0] = '\0';
130
131 /* Get salamander config file path */
132 if (!string_is_empty(rarch_config_path))
133 fill_pathname_resolve_relative(config_path,
134 rarch_config_path,
135 FILE_PATH_SALAMANDER_CONFIG,
136 sizeof(config_path));
137 else
138 strcpy_literal(config_path, FILE_PATH_SALAMANDER_CONFIG);
139
140 /* Ensure that config directory exists */
141 fill_pathname_parent_dir(config_dir, config_path, sizeof(config_dir));
142 if (!string_is_empty(config_dir) &&
143 !path_is_directory(config_dir))
144 path_mkdir(config_dir);
145
146 /* Attempt to open config file */
147 config = config_file_new_from_path_to_string(config_path);
148
149 if (config)
150 {
151 char libretro_path[PATH_MAX_LENGTH];
152
153 libretro_path[0] = '\0';
154
155 if (config_get_path(config, "libretro_path",
156 libretro_path, sizeof(libretro_path)) &&
157 !string_is_empty(libretro_path) &&
158 !string_is_equal(libretro_path, "builtin"))
159 {
160 strlcpy(s, libretro_path, len);
161 config_valid = true;
162 }
163
164 config_file_free(config);
165 config = NULL;
166 }
167
168 if (!config_valid)
169 {
170 char executable_name[PATH_MAX_LENGTH];
171
172 executable_name[0] = '\0';
173
174 /* No config file - search filesystem for
175 * first available core */
176 frontend_driver_get_core_extension(
177 executable_name, sizeof(executable_name));
178 find_and_set_first_file(s, len, executable_name);
179
180 /* Save result to new config file */
181 if (!string_is_empty(s))
182 {
183 config = config_file_new_alloc();
184
185 if (config)
186 {
187 config_set_path(config, "libretro_path", s);
188 config_file_write(config, config_path, false);
189 config_file_free(config);
190 }
191 }
192 }
193 else
194 RARCH_LOG("Start [%s] found in %s.\n", s,
195 FILE_PATH_SALAMANDER_CONFIG);
196 }
197
198 #ifdef HAVE_MAIN
salamander_main(int argc,char * argv[])199 int salamander_main(int argc, char *argv[])
200 #else
201 int main(int argc, char *argv[])
202 #endif
203 {
204 char libretro_path[PATH_MAX_LENGTH] = {0};
205 void *args = NULL;
206 struct rarch_main_wrap *wrap_args = NULL;
207 frontend_ctx_driver_t *frontend_ctx = (frontend_ctx_driver_t*)frontend_ctx_init_first();
208
209 if (!frontend_ctx)
210 return 0;
211
212 if (frontend_ctx && frontend_ctx->init)
213 frontend_ctx->init(args);
214
215 if (frontend_ctx && frontend_ctx->environment_get)
216 frontend_ctx->environment_get(&argc, argv, args, wrap_args);
217
218 salamander_init(libretro_path, sizeof(libretro_path));
219
220 if (frontend_ctx && frontend_ctx->deinit)
221 frontend_ctx->deinit(args);
222
223 if (frontend_ctx && frontend_ctx->exitspawn)
224 frontend_ctx->exitspawn(libretro_path, sizeof(libretro_path), NULL);
225
226 return 1;
227 }
228