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       "wswan_rotate_keymap",
54       "Rotate button mappings",
55       "",
56       {
57          { "auto",  NULL },
58          { "disabled",  NULL },
59          { "enabled",  NULL },
60          { NULL, NULL},
61       },
62       "auto",
63    },
64    {
65       "wswan_sound_sample_rate",
66       "Sound Output Sample Rate",
67       "Slightly higher quality or higher performance.",
68       {
69          { "11025", NULL },
70          { "22050", NULL },
71          { "44100", NULL },
72          { "48000", NULL },
73          { "96000", NULL },
74          { "192000", NULL },
75          { "384000", NULL },
76          { NULL, NULL },
77       },
78       "44100",
79    },
80    {
81       "wswan_gfx_colors",
82       "Color Depth",
83       "24-bit is slower and not available on all platforms.",
84       {
85          { "16bit", "Thousands (16-bit)" },
86          { "24bit", "Millions (24-bit)" },
87          { NULL, NULL },
88       },
89       "16bit"
90    },
91    { NULL, NULL, NULL, { NULL, NULL }, NULL },
92 };
93 
94 /*
95  ********************************
96  * Language Mapping
97  ********************************
98 */
99 
100 #ifndef HAVE_NO_LANGEXTRA
101 struct retro_core_option_definition *option_defs_intl[RETRO_LANGUAGE_LAST] = {
102    option_defs_us, /* RETRO_LANGUAGE_ENGLISH */
103    NULL,           /* RETRO_LANGUAGE_JAPANESE */
104    NULL,           /* RETRO_LANGUAGE_FRENCH */
105    NULL,           /* RETRO_LANGUAGE_SPANISH */
106    NULL,           /* RETRO_LANGUAGE_GERMAN */
107    NULL,           /* RETRO_LANGUAGE_ITALIAN */
108    NULL,           /* RETRO_LANGUAGE_DUTCH */
109    NULL,           /* RETRO_LANGUAGE_PORTUGUESE_BRAZIL */
110    NULL,           /* RETRO_LANGUAGE_PORTUGUESE_PORTUGAL */
111    NULL,           /* RETRO_LANGUAGE_RUSSIAN */
112    NULL,           /* RETRO_LANGUAGE_KOREAN */
113    NULL,           /* RETRO_LANGUAGE_CHINESE_TRADITIONAL */
114    NULL,           /* RETRO_LANGUAGE_CHINESE_SIMPLIFIED */
115    NULL,           /* RETRO_LANGUAGE_ESPERANTO */
116    NULL,           /* RETRO_LANGUAGE_POLISH */
117    NULL,           /* RETRO_LANGUAGE_VIETNAMESE */
118    NULL,           /* RETRO_LANGUAGE_ARABIC */
119    NULL,           /* RETRO_LANGUAGE_GREEK */
120    option_defs_tr, /* RETRO_LANGUAGE_TURKISH */
121 };
122 #endif
123 
124 /*
125  ********************************
126  * Functions
127  ********************************
128 */
129 
130 /* Handles configuration/setting of core options.
131  * Should be called as early as possible - ideally inside
132  * retro_set_environment(), and no later than retro_load_game()
133  * > We place the function body in the header to avoid the
134  *   necessity of adding more .c files (i.e. want this to
135  *   be as painless as possible for core devs)
136  */
137 
libretro_set_core_options(retro_environment_t environ_cb)138 static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
139 {
140    unsigned version = 0;
141 
142    if (!environ_cb)
143       return;
144 
145    if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
146    {
147 #ifndef HAVE_NO_LANGEXTRA
148       struct retro_core_options_intl core_options_intl;
149       unsigned language = 0;
150 
151       core_options_intl.us    = option_defs_us;
152       core_options_intl.local = NULL;
153 
154       if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
155           (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
156          core_options_intl.local = option_defs_intl[language];
157 
158       environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
159 #else
160       environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
161 #endif
162    }
163    else
164    {
165       size_t i;
166       size_t num_options               = 0;
167       struct retro_variable *variables = NULL;
168       char **values_buf                = NULL;
169 
170       /* Determine number of options */
171       while (true)
172       {
173          if (option_defs_us[num_options].key)
174             num_options++;
175          else
176             break;
177       }
178 
179       /* Allocate arrays */
180       variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
181       values_buf = (char **)calloc(num_options, sizeof(char *));
182 
183       if (!variables || !values_buf)
184          goto error;
185 
186       /* Copy parameters from option_defs_us array */
187       for (i = 0; i < num_options; i++)
188       {
189          const char *key                        = option_defs_us[i].key;
190          const char *desc                       = option_defs_us[i].desc;
191          const char *default_value              = option_defs_us[i].default_value;
192          struct retro_core_option_value *values = option_defs_us[i].values;
193          size_t buf_len                         = 3;
194          size_t default_index                   = 0;
195 
196          values_buf[i] = NULL;
197 
198          if (desc)
199          {
200             size_t num_values = 0;
201 
202             /* Determine number of values */
203             while (true)
204             {
205                if (values[num_values].value)
206                {
207                   /* Check if this is the default value */
208                   if (default_value)
209                      if (strcmp(values[num_values].value, default_value) == 0)
210                         default_index = num_values;
211 
212                   buf_len += strlen(values[num_values].value);
213                   num_values++;
214                }
215                else
216                   break;
217             }
218 
219             /* Build values string */
220             if (num_values > 0)
221             {
222                size_t j;
223 
224                buf_len += num_values - 1;
225                buf_len += strlen(desc);
226 
227                values_buf[i] = (char *)calloc(buf_len, sizeof(char));
228                if (!values_buf[i])
229                   goto error;
230 
231                strcpy(values_buf[i], desc);
232                strcat(values_buf[i], "; ");
233 
234                /* Default value goes first */
235                strcat(values_buf[i], values[default_index].value);
236 
237                /* Add remaining values */
238                for (j = 0; j < num_values; j++)
239                {
240                   if (j != default_index)
241                   {
242                      strcat(values_buf[i], "|");
243                      strcat(values_buf[i], values[j].value);
244                   }
245                }
246             }
247          }
248 
249          variables[i].key   = key;
250          variables[i].value = values_buf[i];
251       }
252 
253       /* Set variables */
254       environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
255 
256 error:
257 
258       /* Clean up */
259       if (values_buf)
260       {
261          for (i = 0; i < num_options; i++)
262          {
263             if (values_buf[i])
264             {
265                free(values_buf[i]);
266                values_buf[i] = NULL;
267             }
268          }
269 
270          free(values_buf);
271          values_buf = NULL;
272       }
273 
274       if (variables)
275       {
276          free(variables);
277          variables = NULL;
278       }
279    }
280 }
281 
282 #ifdef __cplusplus
283 }
284 #endif
285 
286 #endif
287