git subrepo clone https://github.com/libretro/libretro-common.git deps/libretro-common
[pcsx_rearmed.git] / deps / libretro-common / samples / core_options / example_translation / libretro_core_options.h
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    NULL,           /* RETRO_LANGUAGE_FINNISH */
124    NULL,           /* RETRO_LANGUAGE_INDONESIAN */
125    NULL,           /* RETRO_LANGUAGE_SWEDISH */
126    NULL,           /* RETRO_LANGUAGE_UKRAINIAN */
127    NULL,           /* RETRO_LANGUAGE_CZECH */
128 };
129 #endif
130
131 /*
132  ********************************
133  * Functions
134  ********************************
135 */
136
137 /* Handles configuration/setting of core options.
138  * Should be called as early as possible - ideally inside
139  * retro_set_environment(), and no later than retro_load_game()
140  * > We place the function body in the header to avoid the
141  *   necessity of adding more .c files (i.e. want this to
142  *   be as painless as possible for core devs)
143  */
144
145 static INLINE void libretro_set_core_options(retro_environment_t environ_cb)
146 {
147    unsigned version = 0;
148
149    if (!environ_cb)
150       return;
151
152    if (environ_cb(RETRO_ENVIRONMENT_GET_CORE_OPTIONS_VERSION, &version) && (version >= 1))
153    {
154 #ifndef HAVE_NO_LANGEXTRA
155       struct retro_core_options_intl core_options_intl;
156       unsigned language = 0;
157
158       core_options_intl.us    = option_defs_us;
159       core_options_intl.local = NULL;
160
161       if (environ_cb(RETRO_ENVIRONMENT_GET_LANGUAGE, &language) &&
162           (language < RETRO_LANGUAGE_LAST) && (language != RETRO_LANGUAGE_ENGLISH))
163          core_options_intl.local = option_defs_intl[language];
164
165       environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS_INTL, &core_options_intl);
166 #else
167       environ_cb(RETRO_ENVIRONMENT_SET_CORE_OPTIONS, &option_defs_us);
168 #endif
169    }
170    else
171    {
172       size_t i;
173       size_t num_options               = 0;
174       struct retro_variable *variables = NULL;
175       char **values_buf                = NULL;
176
177       /* Determine number of options */
178       for (;;)
179       {
180          if (!option_defs_us[num_options].key)
181             break;
182          num_options++;
183       }
184
185       /* Allocate arrays */
186       variables  = (struct retro_variable *)calloc(num_options + 1, sizeof(struct retro_variable));
187       values_buf = (char **)calloc(num_options, sizeof(char *));
188
189       if (!variables || !values_buf)
190          goto error;
191
192       /* Copy parameters from option_defs_us array */
193       for (i = 0; i < num_options; i++)
194       {
195          const char *key                        = option_defs_us[i].key;
196          const char *desc                       = option_defs_us[i].desc;
197          const char *default_value              = option_defs_us[i].default_value;
198          struct retro_core_option_value *values = option_defs_us[i].values;
199          size_t buf_len                         = 3;
200          size_t default_index                   = 0;
201
202          values_buf[i] = NULL;
203
204          if (desc)
205          {
206             size_t num_values = 0;
207
208             /* Determine number of values */
209             for (;;)
210             {
211                if (!values[num_values].value)
212                   break;
213
214                /* Check if this is the default value */
215                if (default_value)
216                   if (strcmp(values[num_values].value, default_value) == 0)
217                      default_index = num_values;
218
219                buf_len += strlen(values[num_values].value);
220                num_values++;
221             }
222
223             /* Build values string */
224             if (num_values > 0)
225             {
226                size_t j;
227
228                buf_len += num_values - 1;
229                buf_len += strlen(desc);
230
231                values_buf[i] = (char *)calloc(buf_len, sizeof(char));
232                if (!values_buf[i])
233                   goto error;
234
235                strcpy(values_buf[i], desc);
236                strcat(values_buf[i], "; ");
237
238                /* Default value goes first */
239                strcat(values_buf[i], values[default_index].value);
240
241                /* Add remaining values */
242                for (j = 0; j < num_values; j++)
243                {
244                   if (j != default_index)
245                   {
246                      strcat(values_buf[i], "|");
247                      strcat(values_buf[i], values[j].value);
248                   }
249                }
250             }
251          }
252
253          variables[i].key   = key;
254          variables[i].value = values_buf[i];
255       }
256
257       /* Set variables */
258       environ_cb(RETRO_ENVIRONMENT_SET_VARIABLES, variables);
259
260 error:
261
262       /* Clean up */
263       if (values_buf)
264       {
265          for (i = 0; i < num_options; i++)
266          {
267             if (values_buf[i])
268             {
269                free(values_buf[i]);
270                values_buf[i] = NULL;
271             }
272          }
273
274          free(values_buf);
275          values_buf = NULL;
276       }
277
278       if (variables)
279       {
280          free(variables);
281          variables = NULL;
282       }
283    }
284 }
285
286 #ifdef __cplusplus
287 }
288 #endif
289
290 #endif