1 #ifndef LIBRETRO_CORE_OPTIONS_H__
2 #define LIBRETRO_CORE_OPTIONS_H__
3
4 #include <stdlib.h>
5 #include <string.h>
6
7 #include <libretro.h>
8 #include <retro_inline.h>
9
10 #ifndef HAVE_NO_LANGEXTRA
11 #include "libretro_core_options_intl.h"
12 #endif
13
14 /*
15 ********************************
16 * VERSION: 1.3
17 ********************************
18 *
19 * - 1.3: Move translations to libretro_core_options_intl.h
20 * - libretro_core_options_intl.h includes BOM and utf-8
21 * fix for MSVC 2010-2013
22 * - Added HAVE_NO_LANGEXTRA flag to disable translations
23 * on platforms/compilers without BOM support
24 * - 1.2: Use core options v1 interface when
25 * RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION is >= 1
26 * (previously required RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION == 1)
27 * - 1.1: Support generation of core options v0 retro_core_option_value
28 * arrays containing options with a single value
29 * - 1.0: First commit
30 */
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 /*
37 ********************************
38 * Core Option Definitions
39 ********************************
40 */
41
42 /* RETRO_LANGUAGE_ENGLISH */
43
44 /* Default language:
45 * - All other languages must include the same keys and values
46 * - Will be used as a fallback in the event that frontend language
47 * is not available
48 * - Will be used as a fallback for any missing entries in
49 * frontend language definition */
50
51 struct retro_core_option_definition option_defs_us[] = {
52 {
53 "mycore_region", /* key (option name) */
54 "Console Region", /* description (label) */
55 "Specify which region the system is from.", /* sublabel */
56 {
57 { "auto", "Auto" }, /* value_1, value_1_label */
58 { "ntsc-j", "Japan" }, /* value_2, value_2_label */
59 { "ntsc-u", "America" }, /* value_3, value_3_label */
60 { "pal", "Europe" }, /* value_4, value_4_label */
61 { NULL, NULL },
62 },
63 "auto" /* default_value */
64 },
65 {
66 "mycore_video_scale",
67 "Video Scale",
68 "Set internal video scale factor.",
69 {
70 { "1x", NULL }, /* If value itself is human-readable (e.g. a number) */
71 { "2x", NULL }, /* and can displayed directly, the value_label should */
72 { "3x", NULL }, /* be set to NULL */
73 { "4x", NULL },
74 { NULL, NULL },
75 },
76 "3x"
77 },
78 {
79 "mycore_overclock",
80 "Reduce Slowdown",
81 "Enable CPU overclock (unsafe).",
82 {
83 { "enabled", NULL }, /* If value is equal to 'enabled' or 'disabled', */
84 { "disabled", NULL }, /* value_label should be set to NULL */
85 { NULL, NULL },
86 },
87 "disabled"
88 },
89 { NULL, NULL, NULL, {{0}}, NULL },
90 };
91
92 /*
93 ********************************
94 * Language Mapping
95 ********************************
96 */
97
98 #ifndef HAVE_NO_LANGEXTRA
99 struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
100 option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
101 NULL, /* RETRO_LANGUAGE_JAPANESE */
102 option_defs_fr, /* RETRO_LANGUAGE_FRENCH */
103 NULL, /* RETRO_LANGUAGE_SPANISH */
104 NULL, /* RETRO_LANGUAGE_GERMAN */
105 NULL, /* RETRO_LANGUAGE_ITALIAN */
106 NULL, /* RETRO_LANGUAGE_DUTCH */
107 NULL, /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
108 NULL, /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
109 NULL, /* RETRO_LANGUAGE_RUSSIAN */
110 NULL, /* RETRO_LANGUAGE_KOREAN */
111 NULL, /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
112 NULL, /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
113 NULL, /* RETRO_LANGUAGE_ESPERANTO */
114 NULL, /* RETRO_LANGUAGE_POLISH */
115 NULL, /* RETRO_LANGUAGE_VIETNAMESE */
116 NULL, /* RETRO_LANGUAGE_ARABIC */
117 NULL, /* RETRO_LANGUAGE_GREEK */
118 NULL, /* RETRO_LANGUAGE_TURKISH */
119 NULL, /* RETRO_LANGUAGE_SLOVAK */
120 NULL, /* RETRO_LANGUAGE_PERSIAN */
121 NULL, /* RETRO_LANGUAGE_HEBREW */
122 NULL, /* RETRO_LANGUAGE_ASTURIAN */
123 };
124 #endif
125
126 /*
127 ********************************
128 * Functions
129 ********************************
130 */
131
132 /* Handles configuration/setting of core options.
133 * Should be called as early as possible - ideally inside
134 * retro_set_environment(), and no later than retro_load_game()
135 * > We place the function body in the header to avoid the
136 * necessity of adding more .c files (i.e. want this to
137 * be as painless as possible for core devs)
138 */
139
libretro_set_core_options(retro_environment_t environ_cb)140 static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
141 {
142 unsigned version = 0;
143
144 if (!environ_cb)
145 return;
146
147 if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
148 {
149 #ifndef HAVE_NO_LANGEXTRA
150 struct retro_core_options_intl core_options_intl;
151 unsigned language = 0;
152
153 core_options_intl.us = option_defs_us;
154 core_options_intl.local = NULL;
155
156 if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
157 (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
158 core_options_intl.local = option_defs_intl[language];
159
160 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
161 #else
162 environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
163 #endif
164 }
165 else
166 {
167 size_t i;
168 size_t num_options = 0;
169 struct retro_variable *variables = NULL;
170 char **values_buf = NULL;
171
172 /* Determine number of options */
173 for (;;)
174 {
175 if (!option_defs_us[num_options].key)
176 break;
177 num_options++;
178 }
179
180 /* Allocate arrays */
181 variables = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
182 values_buf = (char **)calloc(num_options, sizeof(char *));
183
184 if (!variables || !values_buf)
185 goto error;
186
187 /* Copy parameters from option_defs_us array */
188 for (i = 0; i < num_options; i++)
189 {
190 const char *key = option_defs_us[i].key;
191 const char *desc = option_defs_us[i].desc;
192 const char *default_value = option_defs_us[i].default_value;
193 struct retro_core_option_value *values = option_defs_us[i].values;
194 size_t buf_len = 3;
195 size_t default_index = 0;
196
197 values_buf[i] = NULL;
198
199 if (desc)
200 {
201 size_t num_values = 0;
202
203 /* Determine number of values */
204 for (;;)
205 {
206 if (!values[num_values].value)
207 break;
208
209 /* Check if this is the default value */
210 if (default_value)
211 if (strcmp(values[num_values].value, default_value) == 0)
212 default_index = num_values;
213
214 buf_len += strlen(values[num_values].value);
215 num_values++;
216 }
217
218 /* Build values string */
219 if (num_values > 0)
220 {
221 size_t j;
222
223 buf_len += num_values - 1;
224 buf_len += strlen(desc);
225
226 values_buf[i] = (char *)calloc(buf_len, sizeof(char));
227 if (!values_buf[i])
228 goto error;
229
230 strcpy(values_buf[i], desc);
231 strcat(values_buf[i], "; ");
232
233 /* Default value goes first */
234 strcat(values_buf[i], values[default_index].value);
235
236 /* Add remaining values */
237 for (j = 0; j < num_values; j++)
238 {
239 if (j != default_index)
240 {
241 strcat(values_buf[i], "|");
242 strcat(values_buf[i], values[j].value);
243 }
244 }
245 }
246 }
247
248 variables[i].key = key;
249 variables[i].value = values_buf[i];
250 }
251
252 /* Set variables */
253 environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
254
255 error:
256
257 /* Clean up */
258 if (values_buf)
259 {
260 for (i = 0; i < num_options; i++)
261 {
262 if (values_buf[i])
263 {
264 free(values_buf[i]);
265 values_buf[i] = NULL;
266 }
267 }
268
269 free(values_buf);
270 values_buf = NULL;
271 }
272
273 if (variables)
274 {
275 free(variables);
276 variables = NULL;
277 }
278 }
279 }
280
281 #ifdef __cplusplus
282 }
283 #endif
284
285 #endif
286