1 /*
2  * parameters.cpp - parameter init/load/save code
3  *
4  * Copyright (c) 2001-2010 ARAnyM developer team (see AUTHORS)
5  *
6  * Authors:
7  *  MJ		Milan Jurik
8  *  Joy		Petr Stehlik
9  *
10  * This file is part of the ARAnyM project which builds a new and powerful
11  * TOS/FreeMiNT compatible virtual machine running on almost any hardware.
12  *
13  * ARAnyM is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * ARAnyM is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with ARAnyM; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 
28 
29 #include "sysdeps.h"
30 #include "parameters.h"
31 #include "tools.h"		// for safe_strncpy()
32 #include "host.h"
33 #include "host_filesys.h"
34 #include "cfgopts.h"
35 #include "natfeat/nf_base.h"
36 #include "rtc.h"
37 #include "vm_alloc.h"
38 #include "main.h"
39 
40 #define DEBUG 0
41 #include "debug.h"
42 
43 #include <cstdlib>
44 
45 #ifdef OS_darwin
46 #  include <CoreFoundation/CoreFoundation.h>
47 #endif
48 
49 #ifndef USE_JIT
50 # define USE_JIT 0
51 #endif
52 
53 #ifndef USE_JIT_FPU
54 # define USE_JIT_FPU 0
55 #endif
56 
57 #if defined(HW_SIGSEGV)
58 # define MEMORY_CHECK "sseg"
59 #elif defined(EXTENDED_SIGSEGV) && defined(ARAM_PAGE_CHECK)
60 # define MEMORY_CHECK "pagehwsp"
61 #elif defined(EXTENDED_SIGSEGV)
62 # define MEMORY_CHECK "hwsp"
63 #elif defined(ARAM_PAGE_CHECK)
64 # define MEMORY_CHECK "page"
65 #elif defined(NOCHECKBOUNDARY)
66 # define MEMORY_CHECK "none"
67 #else
68 # define MEMORY_CHECK "full"
69 #endif
70 
71 #ifndef FULLMMU
72 # define FULLMMU 0
73 #endif
74 
75 #ifndef DSP_EMULATION
76 # define DSP_EMULATION 0
77 #endif
78 
79 #ifndef DSP_DISASM
80 # define DSP_DISASM 0
81 #endif
82 
83 #ifndef ENABLE_OPENGL
84 # define ENABLE_OPENGL 0
85 #endif
86 
87 #ifndef HOSTFS_SUPPORT
88 # define HOSTFS_SUPPORT 0
89 #endif
90 
91 #ifndef USES_FPU_CORE
92 # define USES_FPU_CORE "<undefined>"
93 #endif
94 
95 #ifndef PROVIDES_NATFEATS
96 # define PROVIDES_NATFEATS "<undefined>"
97 #endif
98 
99 enum {
100 	OPT_PROBE_FIXED = 256,
101 	OPT_FIXEDMEM_OFFSET,
102 	OPT_SET_OPTION
103 };
104 
105 static struct option const long_options[] =
106 {
107 #ifndef FixedSizeFastRAM
108   {"fastram", required_argument, 0, 'F'},
109 #endif
110   {"floppy", required_argument, 0, 'a'},
111   {"resolution", required_argument, 0, 'r'},
112 #ifdef DEBUGGER
113   {"debug", no_argument, 0, 'D'},
114 #endif
115   {"fullscreen", no_argument, 0, 'f'},
116   {"nomouse", no_argument, 0, 'N'},
117   {"refresh", required_argument, 0, 'v'},
118   {"monitor", required_argument, 0, 'm'},
119 #if HOSTFS_SUPPORT
120   {"disk", required_argument, 0, 'd'},
121 #endif
122   {"help", no_argument, 0, 'h'},
123   {"version", no_argument, 0, 'V'},
124   {"config", required_argument, 0, 'c'},
125   {"save", no_argument, 0, 's'},
126 #ifdef SDL_GUI
127   {"gui", no_argument, 0, 'G'},
128 #endif
129   {"swap-ide", no_argument, 0, 'S'},
130   {"emutos", no_argument, 0, 'e'},
131   {"locale", required_argument, 0, 'k'},
132 #ifdef ENABLE_LILO
133   {"lilo", no_argument, 0, 'l'},
134 #endif
135   {"display", required_argument, 0, 'P'},
136 #if FIXED_ADDRESSING
137   {"probe-fixed", no_argument, 0, OPT_PROBE_FIXED },
138   {"fixedmem", required_argument, 0, OPT_FIXEDMEM_OFFSET },
139 #endif
140   {"option", required_argument, 0, OPT_SET_OPTION },
141   {NULL, 0, NULL, 0}
142 };
143 
144 #define TOS_FILENAME		"ROM"
145 #define EMUTOS_FILENAME		"emutos-aranym.img"
146 #define FREEMINT_FILENAME	"mintara.prg"
147 
148 #ifndef DEFAULT_SERIAL
149 #define DEFAULT_SERIAL "/dev/ttyS0"
150 #endif
151 
152 char *program_name;		// set by main()
153 
154 bool boot_emutos = false;
155 bool boot_lilo = false;
156 bool halt_on_reboot = false;
157 bool ide_swap = false;
158 uint32 FastRAMSize;
159 #if FIXED_ADDRESSING
160 uintptr fixed_memory_offset = FMEMORY;
161 #endif
162 
163 static char config_file[512];
164 
165 #if !defined(XIF_HOST_IP) && !defined(XIF_ATARI_IP) && !defined(XIF_NETMASK)
166 # define XIF_TYPE	"ptp"
167 # define XIF_TUNNEL	"tap0"
168 # define XIF_HOST_IP	"192.168.0.1"
169 # define XIF_ATARI_IP	"192.168.0.2"
170 # define XIF_NETMASK	"255.255.255.0"
171 # define XIF_MAC_ADDR	"00:41:45:54:48:30"		// just made up from \0AETH0
172 #endif
173 
174 static bool saveConfigFile = false;
175 
176 bx_options_t bx_options;
177 
178 static bx_atadevice_options_t *diskc = &bx_options.atadevice[0][0];
179 static bx_atadevice_options_t *diskd = &bx_options.atadevice[0][1];
180 
181 #if defined(__IRIX__)
182 /* IRIX doesn't have a GL library versioning system */
183 #define DEFAULT_OPENGL	"libGL.so"
184 #elif defined(__MACOSX__)
185 /* note: this is the Quartz version, not the X11 version */
186 #define DEFAULT_OPENGL	"/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
187 #elif defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
188 /* note: this is the Windows version, not the cygwin version */
189 #define DEFAULT_OPENGL	"opengl32.dll"
190 #define DEFAULT_OSMESA  ""
191 #elif defined(__QNXNTO__)
192 #define DEFAULT_OPENGL	"libGL.so:libGL.so.3"
193 #elif defined(__OpenBSD__)
194 #define DEFAULT_OPENGL	"libGL.so:libGL.so.16.0:libGL.so.15.0:libGL.so.14.0"
195 #else
196 #define DEFAULT_OPENGL	"libGL.so:libGL.so.1"
197 #endif
198 #ifndef DEFAULT_OSMESA
199 #define DEFAULT_OSMESA	"libOSMesa.so:libOSMesa.8.so:libOSMesa.7.so:libOSMesa.6.so"
200 #endif
201 
202 
203 // configuration file
204 /*************************************************************************/
205 
206 static struct {
207 	SDL_Keycode current;
208 	int sdl1;
209 	const char *name;
210 } const sdl_keysyms[] = {
211 	{ SDLK_BACKSPACE, 8, "Backspace" },
212 	{ SDLK_TAB, 9, "Tab" },
213 	{ SDLK_CLEAR, 12, "Clear" },
214 	{ SDLK_RETURN, 13, "Return" },
215 	{ SDLK_PAUSE, 19, "Pause" },
216 	{ SDLK_ESCAPE, 27, "Escape" },
217 	{ SDLK_SPACE, 32, "Space" },
218 
219 	{ SDLK_EXCLAIM, 33, "!" },
220 	{ SDLK_QUOTEDBL, 34, "\"" },
221 	{ SDLK_HASH, 35, "#" },
222 	{ SDLK_DOLLAR, 36, "$" },
223 	{ SDLK_AMPERSAND, 38, "&" },
224 	{ SDLK_QUOTE, 39, "'" },
225 	{ SDLK_LEFTPAREN, 40, "(" },
226 	{ SDLK_RIGHTPAREN, 41, ")" },
227 	{ SDLK_ASTERISK, 42, "*" },
228 	{ SDLK_PLUS, 43, "+" },
229 	{ SDLK_COMMA, 44, "," },
230 	{ SDLK_MINUS, 45, "-" },
231 	{ SDLK_PERIOD, 46, "." },
232 	{ SDLK_SLASH, 47, "/" },
233 	{ SDLK_0, 48, "0" },
234 	{ SDLK_1, 49, "1" },
235 	{ SDLK_2, 50, "2" },
236 	{ SDLK_3, 51, "3" },
237 	{ SDLK_4, 52, "4" },
238 	{ SDLK_5, 53, "5" },
239 	{ SDLK_6, 54, "6" },
240 	{ SDLK_7, 55, "7" },
241 	{ SDLK_8, 56, "8" },
242 	{ SDLK_9, 57, "9" },
243 	{ SDLK_COLON, 58, ":" },
244 	{ SDLK_SEMICOLON, 59, ";" },
245 	{ SDLK_LESS, 60, "<" },
246 	{ SDLK_EQUALS, 61, "=" },
247 	{ SDLK_GREATER, 62, ">" },
248 	{ SDLK_QUESTION, 63, "?" },
249 	{ SDLK_AT, 64, "@" },
250 	{ SDLK_LEFTBRACKET, 91, "[" },
251 	{ SDLK_BACKSLASH, 92, "\\" },
252 	{ SDLK_RIGHTBRACKET, 93, "]" },
253 	{ SDLK_CARET, 94, "^" },
254 	{ SDLK_UNDERSCORE, 95, "_" },
255 	{ SDLK_BACKQUOTE, 96, "`" },
256 	{ SDLK_a, 97, "a" },
257 	{ SDLK_b, 98, "b" },
258 	{ SDLK_c, 99, "c" },
259 	{ SDLK_d, 100, "d" },
260 	{ SDLK_e, 101, "e" },
261 	{ SDLK_f, 102, "f" },
262 	{ SDLK_g, 103, "g" },
263 	{ SDLK_h, 104, "h" },
264 	{ SDLK_i, 105, "i" },
265 	{ SDLK_j, 106, "j" },
266 	{ SDLK_k, 107, "k" },
267 	{ SDLK_l, 108, "l" },
268 	{ SDLK_m, 109, "m" },
269 	{ SDLK_n, 110, "n" },
270 	{ SDLK_o, 111, "o" },
271 	{ SDLK_p, 112, "p" },
272 	{ SDLK_q, 113, "q" },
273 	{ SDLK_r, 114, "r" },
274 	{ SDLK_s, 115, "s" },
275 	{ SDLK_t, 116, "t" },
276 	{ SDLK_u, 117, "u" },
277 	{ SDLK_v, 118, "v" },
278 	{ SDLK_w, 119, "w" },
279 	{ SDLK_x, 120, "x" },
280 	{ SDLK_y, 121, "y" },
281 	{ SDLK_z, 122, "z" },
282 	{ SDLK_DELETE, 127, "Delete" },
283 /*
284 	{ SDLK_WORLD_0, 160 },
285 	{ SDLK_WORLD_1, 161 },
286 	{ SDLK_WORLD_2, 162 },
287 	{ SDLK_WORLD_3, 163 },
288 	{ SDLK_WORLD_4, 164 },
289 	{ SDLK_WORLD_5, 165 },
290 	{ SDLK_WORLD_6, 166 },
291 	{ SDLK_WORLD_7, 167 },
292 	{ SDLK_WORLD_8, 168 },
293 	{ SDLK_WORLD_9, 169 },
294 	{ SDLK_WORLD_10, 170 },
295 	{ SDLK_WORLD_11, 171 },
296 	{ SDLK_WORLD_12, 172 },
297 	{ SDLK_WORLD_13, 173 },
298 	{ SDLK_WORLD_14, 174 },
299 	{ SDLK_WORLD_15, 175 },
300 	{ SDLK_WORLD_16, 176 },
301 	{ SDLK_WORLD_17, 177 },
302 	{ SDLK_WORLD_18, 178 },
303 	{ SDLK_WORLD_19, 179 },
304 	{ SDLK_WORLD_20, 180 },
305 	{ SDLK_WORLD_21, 181 },
306 	{ SDLK_WORLD_22, 182 },
307 	{ SDLK_WORLD_23, 183 },
308 	{ SDLK_WORLD_24, 184 },
309 	{ SDLK_WORLD_25, 185 },
310 	{ SDLK_WORLD_26, 186 },
311 	{ SDLK_WORLD_27, 187 },
312 	{ SDLK_WORLD_28, 188 },
313 	{ SDLK_WORLD_29, 189 },
314 	{ SDLK_WORLD_30, 190 },
315 	{ SDLK_WORLD_31, 191 },
316 	{ SDLK_WORLD_32, 192 },
317 	{ SDLK_WORLD_33, 193 },
318 	{ SDLK_WORLD_34, 194 },
319 	{ SDLK_WORLD_35, 195 },
320 	{ SDLK_WORLD_36, 196 },
321 	{ SDLK_WORLD_37, 197 },
322 	{ SDLK_WORLD_38, 198 },
323 	{ SDLK_WORLD_39, 199 },
324 	{ SDLK_WORLD_40, 200 },
325 	{ SDLK_WORLD_41, 201 },
326 	{ SDLK_WORLD_42, 202 },
327 	{ SDLK_WORLD_43, 203 },
328 	{ SDLK_WORLD_44, 204 },
329 	{ SDLK_WORLD_45, 205 },
330 	{ SDLK_WORLD_46, 206 },
331 	{ SDLK_WORLD_47, 207 },
332 	{ SDLK_WORLD_48, 208 },
333 	{ SDLK_WORLD_49, 209 },
334 	{ SDLK_WORLD_50, 210 },
335 	{ SDLK_WORLD_51, 211 },
336 	{ SDLK_WORLD_52, 212 },
337 	{ SDLK_WORLD_53, 213 },
338 	{ SDLK_WORLD_54, 214 },
339 	{ SDLK_WORLD_55, 215 },
340 	{ SDLK_WORLD_56, 216 },
341 	{ SDLK_WORLD_57, 217 },
342 	{ SDLK_WORLD_58, 218 },
343 	{ SDLK_WORLD_59, 219 },
344 	{ SDLK_WORLD_60, 220 },
345 	{ SDLK_WORLD_61, 221 },
346 	{ SDLK_WORLD_62, 222 },
347 	{ SDLK_WORLD_63, 223 },
348 	{ SDLK_WORLD_64, 224 },
349 	{ SDLK_WORLD_65, 225 },
350 	{ SDLK_WORLD_66, 226 },
351 	{ SDLK_WORLD_67, 227 },
352 	{ SDLK_WORLD_68, 228 },
353 	{ SDLK_WORLD_69, 229 },
354 	{ SDLK_WORLD_70, 230 },
355 	{ SDLK_WORLD_71, 231 },
356 	{ SDLK_WORLD_72, 232 },
357 	{ SDLK_WORLD_73, 233 },
358 	{ SDLK_WORLD_74, 234 },
359 	{ SDLK_WORLD_75, 235 },
360 	{ SDLK_WORLD_76, 236 },
361 	{ SDLK_WORLD_77, 237 },
362 	{ SDLK_WORLD_78, 238 },
363 	{ SDLK_WORLD_79, 239 },
364 	{ SDLK_WORLD_80, 240 },
365 	{ SDLK_WORLD_81, 241 },
366 	{ SDLK_WORLD_82, 242 },
367 	{ SDLK_WORLD_83, 243 },
368 	{ SDLK_WORLD_84, 244 },
369 	{ SDLK_WORLD_85, 245 },
370 	{ SDLK_WORLD_86, 246 },
371 	{ SDLK_WORLD_87, 247 },
372 	{ SDLK_WORLD_88, 248 },
373 	{ SDLK_WORLD_89, 249 },
374 	{ SDLK_WORLD_90, 250 },
375 	{ SDLK_WORLD_91, 251 },
376 	{ SDLK_WORLD_92, 252 },
377 	{ SDLK_WORLD_93, 253 },
378 	{ SDLK_WORLD_94, 254 },
379 	{ SDLK_WORLD_95, 255 },
380 */
381 	{ SDLK_KP_0, 256, "Keypad 0" },
382 	{ SDLK_KP_1, 257, "Keypad 1" },
383 	{ SDLK_KP_2, 258, "Keypad 2" },
384 	{ SDLK_KP_3, 259, "Keypad 3" },
385 	{ SDLK_KP_4, 260, "Keypad 4" },
386 	{ SDLK_KP_5, 261, "Keypad 5" },
387 	{ SDLK_KP_6, 262, "Keypad 6" },
388 	{ SDLK_KP_7, 263, "Keypad 7" },
389 	{ SDLK_KP_8, 264, "Keypad 8" },
390 	{ SDLK_KP_9, 265, "Keypad 9" },
391 	{ SDLK_KP_PERIOD, 266, "Keypad ." },
392 	{ SDLK_KP_DIVIDE, 267, "Keypad /" },
393 	{ SDLK_KP_MULTIPLY, 268, "Keypad *" },
394 	{ SDLK_KP_MINUS, 269, "Keypad -" },
395 	{ SDLK_KP_PLUS, 270, "Keypad +" },
396 	{ SDLK_KP_ENTER, 271, "Keypad Enter" },
397 	{ SDLK_KP_EQUALS, 272, "Keypad =" },
398 	{ SDLK_UP, 273, "Up" },
399 	{ SDLK_DOWN, 274, "Down" },
400 	{ SDLK_RIGHT, 275, "Right" },
401 	{ SDLK_LEFT, 276, "Left" },
402 	{ SDLK_INSERT, 277, "Insert" },
403 	{ SDLK_HOME, 278, "Home" },
404 	{ SDLK_END, 279, "End" },
405 	{ SDLK_PAGEUP, 280, "PageUp" },
406 	{ SDLK_PAGEDOWN, 281, "PageDown" },
407 	{ SDLK_F1, 282, "F1" },
408 	{ SDLK_F2, 283, "F2" },
409 	{ SDLK_F3, 284, "F3" },
410 	{ SDLK_F4, 285, "F4" },
411 	{ SDLK_F5, 286, "F5" },
412 	{ SDLK_F6, 287, "F6" },
413 	{ SDLK_F7, 288, "F7" },
414 	{ SDLK_F8, 289, "F8" },
415 	{ SDLK_F9, 290, "F9" },
416 	{ SDLK_F10, 291, "F10" },
417 	{ SDLK_F11, 292, "F11" },
418 	{ SDLK_F12, 293, "F12" },
419 	{ SDLK_F13, 294, "F13" },
420 	{ SDLK_F14, 295, "F14" },
421 	{ SDLK_F15, 296, "F15" },
422 	{ SDLK_NUMLOCKCLEAR, 300, "Numlock" },
423 	{ SDLK_CAPSLOCK, 301, "CapsLock" },
424 	{ SDLK_SCROLLLOCK, 302, "ScrollLock" },
425 	{ SDLK_RSHIFT, 303, "Right Shift" },
426 	{ SDLK_LSHIFT, 304, "Left Shift" },
427 	{ SDLK_RCTRL, 305, "Right Ctrl" },
428 	{ SDLK_LCTRL, 306, "Left Ctrl" },
429 	{ SDLK_RALT, 307, "Right Alt" },
430 	{ SDLK_LALT, 308, "Left Alt" },
431 	{ SDLK_RGUI, 309, "Right GUI" },
432 	{ SDLK_LGUI, 310, "Left GUI" },
433 //	{ SDLK_LSUPER, 311 },
434 //	{ SDLK_RSUPER, 312 },
435 	{ SDLK_MODE, 313, "ModeSwitch" },
436 //	{ SDLK_COMPOSE, 314 },
437 	{ SDLK_HELP, 315, "Help" },
438 	{ SDLK_PRINTSCREEN, 316, "PrintScreen" },
439 	{ SDLK_SYSREQ, 317, "SysReq" },
440 	{ SDLK_CANCEL, 318, "Cancel" },
441 	{ SDLK_MENU, 319, "Menu" },
442 	{ SDLK_POWER, 320, "Power" },
443 //	{ SDLK_EURO, 321 },
444 	{ SDLK_UNDO, 322, "Undo" },
445 
446 #if SDL_VERSION_ATLEAST(2, 0, 0)
447 	{ SDLK_APPLICATION, 0, "Application" },
448 	{ SDLK_F16, 0, "F16" },
449 	{ SDLK_F17, 0, "F17" },
450 	{ SDLK_F18, 0, "F18" },
451 	{ SDLK_F19, 0, "F19" },
452 	{ SDLK_F20, 0, "F20" },
453 	{ SDLK_F21, 0, "F21" },
454 	{ SDLK_F22, 0, "F22" },
455 	{ SDLK_F23, 0, "F23" },
456 	{ SDLK_F24, 0, "F24" },
457 	{ SDLK_EXECUTE, 0, "Execute" },
458 	{ SDLK_SELECT, 0, "Select" },
459 	{ SDLK_STOP, 0, "Stop" },
460 	{ SDLK_AGAIN, 0, "Again" },
461 	{ SDLK_CUT, 0, "Cut" },
462 	{ SDLK_COPY, 0, "Copy" },
463 	{ SDLK_PASTE, 0, "Paste" },
464 	{ SDLK_FIND, 0, "Find" },
465 	{ SDLK_MUTE, 0, "Mute" },
466 	{ SDLK_VOLUMEUP, 0, "VolumeUp" },
467 	{ SDLK_VOLUMEDOWN, 0, "VolumeDown" },
468 	{ SDLK_KP_COMMA, 0, "Keypad ," },
469 	{ SDLK_PRIOR, 0, "Prior" },
470 	{ SDLK_RETURN2, 0, "Return" },
471 	{ SDLK_SEPARATOR, 0, "Separator" },
472 	{ SDLK_OUT, 0, "Out" },
473 	{ SDLK_OPER, 0, "Oper" },
474 	{ SDLK_CLEARAGAIN, 0, "Clear / Again" },
475 	{ SDLK_CRSEL, 0, "CrSel" },
476 	{ SDLK_EXSEL, 0, "ExSel" },
477 	{ SDLK_KP_00, 0, "Keypad 00" },
478 	{ SDLK_KP_000, 0, "Keypad 000" },
479 	{ SDLK_THOUSANDSSEPARATOR, 0, "ThousandsSeparator" },
480 	{ SDLK_DECIMALSEPARATOR, 0, "DecimalSeparator" },
481 	{ SDLK_CURRENCYUNIT, 0, "CurrencyUnit" },
482 	{ SDLK_CURRENCYSUBUNIT, 0, "CurrencySubUnit" },
483 #endif
484 };
485 
sdl_getkeyname(SDL_Keycode sym)486 static const char *sdl_getkeyname(SDL_Keycode sym)
487 {
488 	for (unsigned int i = 0; i < sizeof(sdl_keysyms) / sizeof(sdl_keysyms[0]); i++)
489 		if (sdl_keysyms[i].current == sym)
490 			return sdl_keysyms[i].name;
491 	return SDL_GetKeyName(sym);
492 }
493 
keysymToString(char * buffer,const bx_hotkey * keysym)494 char *keysymToString(char *buffer, const bx_hotkey *keysym)
495 {
496 	*buffer = 0;
497 	SDL_Keymod mods = keysym->mod;
498 	if (mods & KMOD_LSHIFT) strcat(buffer, "LS+");
499 	if (mods & KMOD_RSHIFT) strcat(buffer, "RS+");
500 	if (mods & KMOD_LCTRL) strcat(buffer, "LC+");
501 	if (mods & KMOD_RCTRL) strcat(buffer, "RC+");
502 	if (mods & KMOD_LALT) strcat(buffer, "LA+");
503 	if (mods & KMOD_RALT) strcat(buffer, "RA+");
504 	if (mods & KMOD_LGUI) strcat(buffer, "LM+");
505 	if (mods & KMOD_RGUI) strcat(buffer, "RM+");
506 	if (mods & KMOD_MODE) strcat(buffer, "MO+");
507 	if (keysym->sym) {
508 		strcat(buffer, sdl_getkeyname(keysym->sym));
509 	} else {
510 		// mod keys only, remove last plus sign
511 		int len = strlen(buffer);
512 		if (len > 0 && buffer[len-1] == '+')
513 			buffer[len-1] = '\0';
514 	}
515 	return buffer;
516 }
517 
stringToKeysym(bx_hotkey * keysym,const char * string)518 bool stringToKeysym(bx_hotkey *keysym, const char *string)
519 {
520 	int sym, mod;
521 	if ( sscanf(string, "%i:%i", &sym, &mod) == 2)
522 	{
523 		/*
524 		 * old format with direct encoding; keysyms are from SDL < 2.0
525 		 * We must translate the SDL 1.2.x values
526 		 */
527 		for (unsigned int i = 0; i < sizeof(sdl_keysyms) / sizeof(sdl_keysyms[0]); i++)
528 		{
529 			if (sym == sdl_keysyms[i].sdl1)
530 			{
531 				keysym->mod = SDL_Keymod(mod);
532 				keysym->sym = sdl_keysyms[i].current;
533 				return true;
534 			}
535 		}
536 		if (mod != 0 && sym == 0)
537 		{
538 			/* modifiers only */
539 			keysym->mod = SDL_Keymod(mod);
540 			keysym->sym = SDLK_UNKNOWN;
541 			return true;
542 		}
543 		return false;
544 	}
545 	mod = 0;
546 #define MOD(s, k) \
547 	if (strncmp(string, s, sizeof(s) - 1) == 0 && \
548 		(string[sizeof(s) - 1] == '+' || string[sizeof(s) - 1] == '\0')) \
549 		{ mod |= k; string += sizeof(s) - 1; if (*string == '+') string++; }
550 	MOD("LS", KMOD_LSHIFT);
551 	MOD("RS", KMOD_RSHIFT);
552 	MOD("LC", KMOD_LCTRL);
553 	MOD("RC", KMOD_RCTRL);
554 	MOD("LA", KMOD_LALT);
555 	MOD("RA", KMOD_RALT);
556 	MOD("LM", KMOD_LGUI);
557 	MOD("RM", KMOD_RGUI);
558 	MOD("MO", KMOD_MODE);
559 #undef MOD
560 	for (unsigned int i = 0; i < sizeof(sdl_keysyms) / sizeof(sdl_keysyms[0]); i++)
561 	{
562 		if (strcmp(sdl_keysyms[i].name, string) == 0)
563 		{
564 			keysym->mod = SDL_Keymod(mod);
565 			keysym->sym = sdl_keysyms[i].current;
566 			return true;
567 		}
568 	}
569 	if (mod != 0)
570 	{
571 		/* modifiers only */
572 		keysym->mod = SDL_Keymod(mod);
573 		keysym->sym = SDLK_UNKNOWN;
574 		return true;
575 	}
576 	return false;
577 }
578 
579 /*
580  * split a pathlist into an array of strings.
581  * returns a single block of malloced memory
582  */
split_pathlist(const char * pathlist)583 char **split_pathlist(const char *pathlist)
584 {
585 	size_t size;
586 	const char *p;
587 	size_t cnt;
588 	char *dst;
589 	char **result;
590 
591 	if (pathlist == NULL)
592 		return NULL;
593 
594 	/* count words */
595 	cnt = 2;
596 	p = pathlist;
597 	while (*p != '\0')
598 	{
599 		if (*p == ';' || *p == ':')
600 			cnt++;
601 		p++;
602 	}
603 
604 	size = (p - pathlist) + cnt * (sizeof(char *) + 2);
605 	result = (char **)malloc(size);
606 	if (result == NULL)
607 		return NULL;
608 
609 	p = pathlist;
610 	dst = (char *)(result + cnt);
611 	cnt = 0;
612 	p = pathlist;
613 	while (*p != '\0')
614 	{
615 		result[cnt] = dst;
616 		while (*p != '\0')
617 		{
618 			if (*p == ';' || *p == ':')
619 			{
620 				size_t len = dst - result[cnt];
621 				if (*p == ':' && len == 1 && isalnum(p[-1]))
622 				{
623 					*dst++ = *p++;
624 					continue;
625 				}
626 				break;
627 			}
628 			*dst++ = *p++;
629 		}
630 		*dst++ = '\0';
631 		cnt++;
632 		if (*p != '\0')
633 			p++;
634 	}
635 	result[cnt] = NULL;
636 	return result;
637 }
638 
639 
640 /*************************************************************************/
641 struct Config_Tag global_conf[]={
642 	{ "FastRAM", Int_Tag, &bx_options.fastram, 0, 0},
643 	{ "FixedMemoryOffset", HexLong_Tag, &bx_options.fixed_memory_offset, 0, 0}, // FIXME: implement Ptr_Tag
644 	{ "Floppy", Path_Tag, bx_options.floppy.path, sizeof(bx_options.floppy.path), 0},
645 	{ "TOS", Path_Tag, bx_options.tos.tos_path, sizeof(bx_options.tos.tos_path), 0},
646 	{ "EmuTOS", Path_Tag, bx_options.tos.emutos_path, sizeof(bx_options.tos.emutos_path), 0},
647 	{ "Bootstrap", Path_Tag, bx_options.bootstrap_path, sizeof(bx_options.bootstrap_path), 0},
648 	{ "BootstrapArgs", String_Tag, bx_options.bootstrap_args, sizeof(bx_options.bootstrap_args), 0},
649 	{ "BootDrive", Char_Tag, &bx_options.bootdrive, 0, 0},
650 	{ "GMTime", Bool_Tag, &bx_options.gmtime, 0, 0},
651 	{ "EpsEnabled", Bool_Tag, &bx_options.cpu.eps_enabled, 0, 0},
652 	{ "EpsMax", Int_Tag, &bx_options.cpu.eps_max, 0, 0},
653 	{ "SnapshotDir", Path_Tag, bx_options.snapshot_dir, sizeof(bx_options.snapshot_dir), 0},
654 	{ NULL , Error_Tag, NULL, 0, 0 }
655 };
656 
preset_global()657 static void preset_global()
658 {
659 	strcpy(bx_options.tos.tos_path, TOS_FILENAME);
660 	strcpy(bx_options.tos.emutos_path, EMUTOS_FILENAME);
661 	strcpy(bx_options.bootstrap_path, FREEMINT_FILENAME);
662 	bx_options.gmtime = false;	// use localtime by default
663 	strcpy(bx_options.floppy.path, "");
664 #ifdef FixedSizeFastRAM
665 	FastRAMSize = FixedSizeFastRAM * 1024 * 1024;
666 #else
667 	FastRAMSize = 0;
668 #endif
669 #if FIXED_ADDRESSING
670 	bx_options.fixed_memory_offset = fixed_memory_offset;
671 #endif
672 	bx_options.cpu.eps_enabled = false;
673 	bx_options.cpu.eps_max = 20;
674 	strcpy(bx_options.snapshot_dir, "snapshots");
675 }
676 
postload_global()677 static void postload_global()
678 {
679 #ifndef FixedSizeFastRAM
680 	FastRAMSize = bx_options.fastram * 1024 * 1024;
681 #endif
682 #if FIXED_ADDRESSING
683 	fixed_memory_offset = bx_options.fixed_memory_offset;
684 	if (fixed_memory_offset == 0)
685 		fixed_memory_offset = FMEMORY;
686 #endif
687 	if (!isalpha(bx_options.bootdrive))
688 		bx_options.bootdrive = 0;
689 }
690 
presave_global()691 static void presave_global()
692 {
693 	bx_options.fastram = FastRAMSize / 1024 / 1024;
694 #if FIXED_ADDRESSING
695 	bx_options.fixed_memory_offset = fixed_memory_offset;
696 #endif
697 	if (bx_options.bootdrive == 0)
698 		bx_options.bootdrive = ' ';
699 }
700 
701 /*************************************************************************/
702 struct Config_Tag startup_conf[]={
703 	{ "GrabMouse", Bool_Tag, &bx_options.startup.grabMouseAllowed, 0, 0},
704 	{ "Debugger", Bool_Tag, &bx_options.startup.debugger, 0, 0},
705 	{ NULL , Error_Tag, NULL, 0, 0 }
706 };
707 
preset_startup()708 static void preset_startup()
709 {
710   bx_options.startup.debugger = false;
711   bx_options.startup.grabMouseAllowed = true;
712 }
713 
postload_startup()714 static void postload_startup()
715 {
716 }
717 
presave_startup()718 static void presave_startup()
719 {
720 }
721 
722 /*************************************************************************/
723 struct Config_Tag jit_conf[]={
724 	{ "JIT", Bool_Tag, &bx_options.jit.jit, 0, 0},
725 	{ "JITFPU", Bool_Tag, &bx_options.jit.jitfpu, 0, 0},
726 	{ "JITCacheSize", Int_Tag, &bx_options.jit.jitcachesize, 0, 0},
727 	{ "JITLazyFlush", Int_Tag, &bx_options.jit.jitlazyflush, 0, 0},
728 	{ "JITBlackList", String_Tag, &bx_options.jit.jitblacklist, sizeof(bx_options.jit.jitblacklist), 0},
729 	{ "JITInline", Bool_Tag, &bx_options.jit.jitinline, 0, 0},
730 	{ "JITDebug", Bool_Tag, &bx_options.jit.jitdebug, 0, 0},
731 	{ NULL , Error_Tag, NULL, 0, 0 }
732 };
733 
preset_jit()734 static void preset_jit()
735 {
736 	bx_options.jit.jit = true;
737 	bx_options.jit.jitfpu = true;
738 	bx_options.jit.jitcachesize = 8192;
739 	bx_options.jit.jitlazyflush = 1;
740 	strcpy(bx_options.jit.jitblacklist, "");
741 }
742 
postload_jit()743 static void postload_jit()
744 {
745 }
746 
presave_jit()747 static void presave_jit()
748 {
749 }
750 
751 /*************************************************************************/
752 struct Config_Tag tos_conf[]={
753 	{ "Cookie_MCH", HexLong_Tag, &bx_options.tos.cookie_mch, 0, 0},
754 	{ "RedirConsole", Bool_Tag, &bx_options.tos.redirect_CON, 0, 0},
755 	{ NULL , Error_Tag, NULL, 0, 0 }
756 };
757 
preset_tos()758 static void preset_tos()
759 {
760   bx_options.tos.redirect_CON = false;
761   bx_options.tos.cookie_mch = 0x00050000; // ARAnyM
762   bx_options.tos.cookie_akp = -1;
763 }
764 
postload_tos()765 static void postload_tos()
766 {
767 }
768 
presave_tos()769 static void presave_tos()
770 {
771 }
772 
773 /*************************************************************************/
774 struct Config_Tag video_conf[]={
775 	{ "FullScreen", Bool_Tag, &bx_options.video.fullscreen, 0, 0},
776 	{ "BootColorDepth", Byte_Tag, &bx_options.video.boot_color_depth, 0, 0},
777 	{ "VidelRefresh", Byte_Tag, &bx_options.video.refresh, 0, 0},
778 	{ "VidelMonitor", Byte_Tag, &bx_options.video.monitor, 0, 0},
779 	{ "SingleBlitComposing", Bool_Tag, &bx_options.video.single_blit_composing, 0, 0},
780 	{ "SingleBlitRefresh", Bool_Tag, &bx_options.video.single_blit_refresh, 0, 0},
781 	{ "WindowPos", String_Tag, bx_options.video.window_pos, sizeof(bx_options.video.window_pos), 0},
782 	{ NULL , Error_Tag, NULL, 0, 0 }
783 };
784 
preset_video()785 static void preset_video()
786 {
787   bx_options.video.fullscreen = false;		// Boot in Fullscreen
788   bx_options.video.boot_color_depth = -1;	// Boot in color depth
789   bx_options.video.monitor = -1;			// preserve default NVRAM monitor
790   bx_options.video.refresh = 2;				// 25 Hz update
791   strcpy(bx_options.video.window_pos, "");	// ARAnyM window position on screen
792   bx_options.video.single_blit_composing = false;	// Use chunky screen composing
793   bx_options.video.single_blit_refresh = false;	// Use chunky screen refreshing
794 }
795 
postload_video()796 static void postload_video()
797 {
798 	if (bx_options.video.refresh < 1 || bx_options.video.refresh > 200)
799 		bx_options.video.refresh = 2;	// default if input parameter is insane
800 }
801 
presave_video()802 static void presave_video()
803 {
804 }
805 
806 /*************************************************************************/
807 struct Config_Tag opengl_conf[]={
808 	{ "Enabled", Bool_Tag, &bx_options.opengl.enabled, 0, 0},
809 	{ "Filtered", Bool_Tag, &bx_options.opengl.filtered, 0, 0},
810 	{ "Library", String_Tag, bx_options.opengl.library, sizeof(bx_options.opengl.library), 0},
811 	{ NULL , Error_Tag, NULL, 0, 0 }
812 };
813 
preset_opengl()814 static void preset_opengl()
815 {
816   bx_options.opengl.enabled = false;
817   bx_options.opengl.filtered = false;
818   strcpy(bx_options.opengl.library, DEFAULT_OPENGL);
819 }
820 
postload_opengl()821 static void postload_opengl()
822 {
823 #ifndef ENABLE_OPENGL
824   bx_options.opengl.enabled = false;
825 #endif
826 }
827 
presave_opengl()828 static void presave_opengl()
829 {
830 }
831 
832 /*************************************************************************/
833 #define BX_DISK_CONFIG(Disk)	struct Config_Tag Disk ## _configs[] = {	\
834 	{ "Present", Bool_Tag, &Disk->present, 0, 0},	\
835 	{ "IsCDROM", Bool_Tag, &Disk->isCDROM, 0, 0},	\
836 	{ "ByteSwap", Bool_Tag, &Disk->byteswap, 0, 0},	\
837 	{ "ReadOnly", Bool_Tag, &Disk->readonly, 0, 0},	\
838 	{ "Path", Path_Tag, Disk->path, sizeof(Disk->path), 0},	\
839 	{ "Cylinders", Int_Tag, &Disk->cylinders, 0, 0},	\
840 	{ "Heads", Int_Tag, &Disk->heads, 0, 0},	\
841 	{ "SectorsPerTrack", Int_Tag, &Disk->spt, 0, 0},	\
842 	{ "ModelName", String_Tag, Disk->model, sizeof(Disk->model), 0},	\
843 	{ NULL , Error_Tag, NULL, 0, 0 }	\
844 }
845 
846 BX_DISK_CONFIG(diskc);
847 BX_DISK_CONFIG(diskd);
848 
set_ide(unsigned int number,const char * dev_path,int cylinders,int heads,int spt,int byteswap,bool readonly,const char * model_name)849 static void set_ide(unsigned int number, const char *dev_path, int cylinders, int heads, int spt, int byteswap, bool readonly, const char *model_name)
850 {
851   // Autodetect ???
852   if (cylinders == -1) {
853     if ((cylinders = get_geometry(dev_path, geoCylinders)) == -1) {
854       panicbug("Disk %s has unknown geometry.", dev_path);
855       exit(EXIT_FAILURE);
856     }
857   }
858 
859   if (heads == -1) {
860     if ((heads = get_geometry(dev_path, geoHeads)) == -1) {
861       panicbug("Disk %s has unknown geometry.", dev_path);
862       exit(EXIT_FAILURE);
863     }
864   }
865 
866   if (spt == -1) {
867     if ((spt = get_geometry(dev_path, geoSpt)) == -1) {
868       panicbug("Disk %s has unknown geometry.", dev_path);
869       exit(EXIT_FAILURE);
870     }
871   }
872 
873   if (byteswap == -1) {
874     if ((byteswap = get_geometry(dev_path, geoByteswap)) == -1) {
875       panicbug("Disk %s has unknown geometry.", dev_path);
876       exit(EXIT_FAILURE);
877     }
878   }
879 
880 	bx_atadevice_options_t *disk;
881 	switch(number) {
882 		case 0: disk = diskc; break;
883 		case 1: disk = diskd; break;
884 		default: disk = NULL; break;
885 	}
886   if (disk != NULL) {
887     disk->present = strlen(dev_path) > 0;
888     disk->isCDROM = false;
889     disk->byteswap = byteswap;
890     disk->readonly = readonly;
891     disk->cylinders = cylinders;
892     disk->heads = heads;
893     disk->spt = spt;
894     strcpy(disk->path, dev_path);
895 	safe_strncpy(disk->model, model_name, sizeof(disk->model));
896   }
897 
898   if (cylinders && heads && spt) {
899     D(bug("IDE%d CHS geometry: %d/%d/%d %d", number, cylinders, heads, spt, byteswap));
900   }
901 
902 }
903 
preset_ide()904 static void preset_ide()
905 {
906   set_ide(0, "", 0, 0, 0, false, false, "Master");
907   set_ide(1, "", 0, 0, 0, false, false, "Slave");
908 
909   bx_options.newHardDriveSupport = true;
910 }
911 
postload_ide()912 static void postload_ide()
913 {
914 }
915 
presave_ide()916 static void presave_ide()
917 {
918 }
919 
920 /*************************************************************************/
921 #define DISK_CONFIG(Disk)	struct Config_Tag Disk ## _configs[] = {	\
922 	{ "Path", Path_Tag, Disk->path, sizeof(Disk->path), 0},	\
923 	{ "Present", Bool_Tag, &Disk->present, 0, 0},	\
924 	{ "PartID", String_Tag, Disk->partID, sizeof(Disk->partID), 0},	\
925 	{ "ByteSwap", Bool_Tag, &Disk->byteswap, 0, 0},	\
926 	{ "ReadOnly", Bool_Tag, &Disk->readonly, 0, 0},	\
927 	{ NULL , Error_Tag, NULL, 0, 0 }	\
928 }
929 
930 static bx_scsidevice_options_t *disk0 = &bx_options.disks[0];
931 static bx_scsidevice_options_t *disk1 = &bx_options.disks[1];
932 static bx_scsidevice_options_t *disk2 = &bx_options.disks[2];
933 static bx_scsidevice_options_t *disk3 = &bx_options.disks[3];
934 static bx_scsidevice_options_t *disk4 = &bx_options.disks[4];
935 static bx_scsidevice_options_t *disk5 = &bx_options.disks[5];
936 static bx_scsidevice_options_t *disk6 = &bx_options.disks[6];
937 static bx_scsidevice_options_t *disk7 = &bx_options.disks[7];
938 
939 DISK_CONFIG(disk0);
940 DISK_CONFIG(disk1);
941 DISK_CONFIG(disk2);
942 DISK_CONFIG(disk3);
943 DISK_CONFIG(disk4);
944 DISK_CONFIG(disk5);
945 DISK_CONFIG(disk6);
946 DISK_CONFIG(disk7);
947 
preset_disk()948 static void preset_disk()
949 {
950 	for(int i=0; i<DISKS; i++) {
951 		*bx_options.disks[i].path = '\0';
952 		bx_options.disks[i].present = false;
953 		strcpy(bx_options.disks[i].partID, "BGM");
954 		bx_options.disks[i].byteswap = false;
955 		bx_options.disks[i].readonly = false;
956 	}
957 }
958 
postload_disk()959 static void postload_disk()
960 {
961 }
962 
presave_disk()963 static void presave_disk()
964 {
965 }
966 
967 /*************************************************************************/
968 #define HOSTFS_ENTRY(c,n) \
969 	{ c, Path_Tag, &bx_options.aranymfs.drive[n].configPath, sizeof(bx_options.aranymfs.drive[n].configPath), 0}
970 
971 struct Config_Tag arafs_conf[]={
972 	{ "symlinks", String_Tag, &bx_options.aranymfs.symlinks, sizeof(bx_options.aranymfs.symlinks), 0},
973 	HOSTFS_ENTRY("A", 0),
974 	HOSTFS_ENTRY("B", 1),
975 	HOSTFS_ENTRY("C", 2),
976 	HOSTFS_ENTRY("D", 3),
977 	HOSTFS_ENTRY("E", 4),
978 	HOSTFS_ENTRY("F", 5),
979 	HOSTFS_ENTRY("G", 6),
980 	HOSTFS_ENTRY("H", 7),
981 	HOSTFS_ENTRY("I", 8),
982 	HOSTFS_ENTRY("J", 9),
983 	HOSTFS_ENTRY("K", 10),
984 	HOSTFS_ENTRY("L", 11),
985 	HOSTFS_ENTRY("M", 12),
986 	HOSTFS_ENTRY("N", 13),
987 	HOSTFS_ENTRY("O", 14),
988 	HOSTFS_ENTRY("P", 15),
989 	HOSTFS_ENTRY("Q", 16),
990 	HOSTFS_ENTRY("R", 17),
991 	HOSTFS_ENTRY("S", 18),
992 	HOSTFS_ENTRY("T", 19),
993 	HOSTFS_ENTRY("U", 20),
994 	HOSTFS_ENTRY("V", 21),
995 	HOSTFS_ENTRY("W", 22),
996 	HOSTFS_ENTRY("X", 23),
997 	HOSTFS_ENTRY("Y", 24),
998 	HOSTFS_ENTRY("Z", 25),
999 	HOSTFS_ENTRY("0", 26),
1000 	HOSTFS_ENTRY("1", 27),
1001 	HOSTFS_ENTRY("2", 28),
1002 	HOSTFS_ENTRY("3", 29),
1003 	HOSTFS_ENTRY("4", 30),
1004 	HOSTFS_ENTRY("5", 31),
1005 	{ NULL , Error_Tag, NULL, 0, 0}
1006 };
1007 
preset_arafs()1008 static void preset_arafs()
1009 {
1010 	strcpy(bx_options.aranymfs.symlinks, "posix");
1011 	for(int i=0; i < HOSTFS_MAX_DRIVES; i++) {
1012 		bx_options.aranymfs.drive[i].rootPath[0] = '\0';
1013 		bx_options.aranymfs.drive[i].configPath[0] = '\0';
1014 		bx_options.aranymfs.drive[i].halfSensitive = true;
1015 	}
1016 }
1017 
postload_arafs()1018 static void postload_arafs()
1019 {
1020 	for(int i=0; i < HOSTFS_MAX_DRIVES; i++) {
1021 		safe_strncpy(bx_options.aranymfs.drive[i].rootPath, bx_options.aranymfs.drive[i].configPath, sizeof(bx_options.aranymfs.drive[i].rootPath));
1022 		int len = strlen(bx_options.aranymfs.drive[i].configPath);
1023 		bx_options.aranymfs.drive[i].halfSensitive = true;
1024 		if (len > 0) {
1025 			char *ptrLast = bx_options.aranymfs.drive[i].rootPath + len-1;
1026 			if (*ptrLast == ':') {
1027 				*ptrLast = '\0';
1028 				bx_options.aranymfs.drive[i].halfSensitive = false;
1029 			}
1030 #if defined(__CYGWIN__) || defined(_WIN32)
1031 			// interpet "C:" here as the root directory of C:, not the current directory
1032 			if (DriveFromLetter(bx_options.aranymfs.drive[i].rootPath[0]) >= 0 &&
1033 				bx_options.aranymfs.drive[i].rootPath[1] == ':' &&
1034 				bx_options.aranymfs.drive[i].rootPath[2] == '\0')
1035 				strcat(bx_options.aranymfs.drive[i].rootPath, DIRSEPARATOR);
1036 #endif
1037 #if defined(__CYGWIN__)
1038 			cygwin_path_to_win32(bx_options.aranymfs.drive[i].rootPath, sizeof(bx_options.aranymfs.drive[i].rootPath));
1039 #endif
1040 			strd2upath(bx_options.aranymfs.drive[i].rootPath, bx_options.aranymfs.drive[i].rootPath);
1041 			len = strlen(bx_options.aranymfs.drive[i].rootPath);
1042 			ptrLast = bx_options.aranymfs.drive[i].rootPath + len-1;
1043 			if (*ptrLast != *DIRSEPARATOR)
1044 				strcat(bx_options.aranymfs.drive[i].rootPath, DIRSEPARATOR);
1045 		}
1046 	}
1047 }
1048 
presave_arafs()1049 static void presave_arafs()
1050 {
1051 	for(int i=0; i < HOSTFS_MAX_DRIVES; i++) {
1052 		safe_strncpy(bx_options.aranymfs.drive[i].configPath, bx_options.aranymfs.drive[i].rootPath, sizeof(bx_options.aranymfs.drive[i].configPath));
1053 		if ( strlen(bx_options.aranymfs.drive[i].rootPath) > 0 &&
1054 			 !bx_options.aranymfs.drive[i].halfSensitive ) {
1055 			// set the halfSensitive indicator
1056 			strcat( bx_options.aranymfs.drive[i].configPath, ":" );
1057 		}
1058 	}
1059 }
1060 
1061 /*************************************************************************/
1062 // struct Config_Tag ethernet_conf[]={
1063 #define ETH_CONFIG(Eth)	struct Config_Tag Eth ## _conf[] = {	\
1064 	{ "Type", String_Tag, &Eth->type, sizeof(Eth->type), 0}, \
1065 	{ "Tunnel", String_Tag, &Eth->tunnel, sizeof(Eth->tunnel), 0}, \
1066 	{ "HostIP", String_Tag, &Eth->ip_host, sizeof(Eth->ip_host), 0}, \
1067 	{ "AtariIP", String_Tag, &Eth->ip_atari, sizeof(Eth->ip_atari), 0}, \
1068 	{ "Netmask", String_Tag, &Eth->netmask, sizeof(Eth->netmask), 0}, \
1069 	{ "MAC", String_Tag, &Eth->mac_addr, sizeof(Eth->mac_addr), 0}, \
1070 	{ NULL , Error_Tag, NULL, 0, 0 } \
1071 }
1072 
1073 static bx_ethernet_options_t *eth0 = &bx_options.ethernet[0];
1074 static bx_ethernet_options_t *eth1 = &bx_options.ethernet[1];
1075 static bx_ethernet_options_t *eth2 = &bx_options.ethernet[2];
1076 static bx_ethernet_options_t *eth3 = &bx_options.ethernet[3];
1077 
1078 ETH_CONFIG(eth0);
1079 ETH_CONFIG(eth1);
1080 ETH_CONFIG(eth2);
1081 ETH_CONFIG(eth3);
1082 
1083 #define ETH(i, x) bx_options.ethernet[i].x
preset_ethernet()1084 static void preset_ethernet()
1085 {
1086 	// ETH[0] with some default values
1087 	safe_strncpy(ETH(0, type), XIF_TYPE, sizeof(ETH(0, type)));
1088 	safe_strncpy(ETH(0, tunnel), XIF_TUNNEL, sizeof(ETH(0, tunnel)));
1089 	safe_strncpy(ETH(0, ip_host), XIF_HOST_IP, sizeof(ETH(0, ip_host)));
1090 	safe_strncpy(ETH(0, ip_atari), XIF_ATARI_IP, sizeof(ETH(0, ip_atari)));
1091 	safe_strncpy(ETH(0, netmask), XIF_NETMASK, sizeof(ETH(0, netmask)));
1092 	safe_strncpy(ETH(0, mac_addr), XIF_MAC_ADDR, sizeof(ETH(0, mac_addr)));
1093 
1094 	// ETH[1] - ETH[MAX_ETH] are empty by default
1095 	for(int i=1; i<MAX_ETH; i++) {
1096 		*ETH(i, type) = '\0';
1097 		*ETH(i, tunnel) = '\0';
1098 		*ETH(i, ip_host) = '\0';
1099 		*ETH(i, ip_atari) = '\0';
1100 		*ETH(i, netmask) = '\0';
1101 		*ETH(i, mac_addr) = '\0';
1102 	}
1103 }
1104 
postload_ethernet()1105 static void postload_ethernet()
1106 {
1107 }
1108 
presave_ethernet()1109 static void presave_ethernet()
1110 {
1111 }
1112 
1113 /*************************************************************************/
1114 #define LILO(x) bx_options.lilo.x
1115 
1116 struct Config_Tag lilo_conf[]={
1117 	{ "Kernel", Path_Tag, &LILO(kernel), sizeof(LILO(kernel)), 0},
1118 	{ "Args", String_Tag, &LILO(args), sizeof(LILO(args)), 0},
1119 	{ "Ramdisk", Path_Tag, &LILO(ramdisk), sizeof(LILO(ramdisk)), 0},
1120 	{ "LoadToFastRam", Bool_Tag, &LILO(load_to_fastram), 0, 0},
1121 	{ NULL , Error_Tag, NULL, 0, 0 }
1122 };
1123 
preset_lilo()1124 static void preset_lilo()
1125 {
1126   safe_strncpy(LILO(kernel), "linux.bin", sizeof(LILO(kernel)));
1127   safe_strncpy(LILO(args), "root=/dev/ram video=atafb:vga16", sizeof(LILO(args)));
1128   safe_strncpy(LILO(ramdisk), "root.bin", sizeof(LILO(ramdisk)));
1129   LILO(load_to_fastram) = false;
1130 }
1131 
postload_lilo()1132 static void postload_lilo()
1133 {
1134 }
1135 
presave_lilo()1136 static void presave_lilo()
1137 {
1138 }
1139 
1140 /*************************************************************************/
1141 #define MIDI(x) bx_options.midi.x
1142 
1143 struct Config_Tag midi_conf[]={
1144 	{ "Type", String_Tag, &MIDI(type), sizeof(MIDI(type)), 0},
1145 	{ "File", Path_Tag, &MIDI(file), sizeof(MIDI(file)), 0},
1146 	{ "Sequencer", Path_Tag, &MIDI(sequencer), sizeof(MIDI(sequencer)), 0},
1147 	{ "Enabled", Bool_Tag, &MIDI(enabled), 0, 0},
1148 	{ NULL , Error_Tag, NULL, 0, 0 }
1149 };
1150 
preset_midi()1151 static void preset_midi() {
1152   safe_strncpy(MIDI(type), "none", sizeof(MIDI(type)));
1153   safe_strncpy(MIDI(file), "", sizeof(MIDI(file)));
1154   safe_strncpy(MIDI(sequencer), "/dev/sequencer", sizeof(MIDI(sequencer)));
1155   MIDI(enabled) = false;
1156 }
1157 
postload_midi()1158 static void postload_midi() {
1159 	MIDI *midi = getMIDI();
1160 	if (midi)
1161 		midi->enable(MIDI(enabled));
1162 }
1163 
presave_midi()1164 static void presave_midi() {
1165 }
1166 
1167 /*************************************************************************/
1168 #define NFCDROM_ENTRY(c,n) \
1169 	{ c, Int_Tag, &bx_options.nfcdroms[n].physdevtohostdev, sizeof(bx_options.nfcdroms[n].physdevtohostdev), 0}
1170 
1171 struct Config_Tag nfcdroms_conf[]={
1172 	NFCDROM_ENTRY("A", 0),
1173 	NFCDROM_ENTRY("B", 1),
1174 	NFCDROM_ENTRY("C", 2),
1175 	NFCDROM_ENTRY("D", 3),
1176 	NFCDROM_ENTRY("E", 4),
1177 	NFCDROM_ENTRY("F", 5),
1178 	NFCDROM_ENTRY("G", 6),
1179 	NFCDROM_ENTRY("H", 7),
1180 	NFCDROM_ENTRY("I", 8),
1181 	NFCDROM_ENTRY("J", 9),
1182 	NFCDROM_ENTRY("K", 10),
1183 	NFCDROM_ENTRY("L", 11),
1184 	NFCDROM_ENTRY("M", 12),
1185 	NFCDROM_ENTRY("N", 13),
1186 	NFCDROM_ENTRY("O", 14),
1187 	NFCDROM_ENTRY("P", 15),
1188 	NFCDROM_ENTRY("Q", 16),
1189 	NFCDROM_ENTRY("R", 17),
1190 	NFCDROM_ENTRY("S", 18),
1191 	NFCDROM_ENTRY("T", 19),
1192 	NFCDROM_ENTRY("U", 20),
1193 	NFCDROM_ENTRY("V", 21),
1194 	NFCDROM_ENTRY("W", 22),
1195 	NFCDROM_ENTRY("X", 23),
1196 	NFCDROM_ENTRY("Y", 24),
1197 	NFCDROM_ENTRY("Z", 25),
1198 	NFCDROM_ENTRY("0", 26),
1199 	NFCDROM_ENTRY("1", 27),
1200 	NFCDROM_ENTRY("2", 28),
1201 	NFCDROM_ENTRY("3", 29),
1202 	NFCDROM_ENTRY("4", 30),
1203 	NFCDROM_ENTRY("5", 31),
1204 	{ NULL , Error_Tag, NULL, 0, 0 }
1205 };
1206 
preset_nfcdroms()1207 static void preset_nfcdroms() {
1208 	for(int i=0; i < CD_MAX_DRIVES; i++) {
1209 		bx_options.nfcdroms[i].physdevtohostdev = -1;
1210 	}
1211 }
1212 
postload_nfcdroms()1213 static void postload_nfcdroms() {
1214 }
1215 
presave_nfcdroms()1216 static void presave_nfcdroms() {
1217 }
1218 
1219 /*************************************************************************/
1220 struct Config_Tag autozoom_conf[]={
1221 	{ "Enabled", Bool_Tag, &bx_options.autozoom.enabled, 0, 0},
1222 	{ "IntegerCoefs", Bool_Tag, &bx_options.autozoom.integercoefs, 0, 0},
1223 	{ "FixedSize", Bool_Tag, &bx_options.autozoom.fixedsize, 0, 0},
1224 	{ "Width", Int_Tag, &bx_options.autozoom.width, 0, 0},
1225 	{ "Height", Int_Tag, &bx_options.autozoom.height, 0, 0},
1226 	{ NULL , Error_Tag, NULL, 0, 0 }
1227 };
1228 
preset_autozoom()1229 static void preset_autozoom() {
1230   bx_options.autozoom.enabled = false;
1231   bx_options.autozoom.integercoefs = false;
1232   bx_options.autozoom.fixedsize = false;
1233   bx_options.autozoom.width = 640;
1234   bx_options.autozoom.height = 480;
1235 }
1236 
postload_autozoom()1237 static void postload_autozoom() {
1238 }
1239 
presave_autozoom()1240 static void presave_autozoom() {
1241 }
1242 
1243 /*************************************************************************/
1244 #define OSMESA_CONF(x) bx_options.osmesa.x
1245 
1246 struct Config_Tag osmesa_conf[]={
1247 	{ "ChannelSize", Int_Tag, &OSMESA_CONF(channel_size), 0, 0},
1248 	{ "LibGL", String_Tag, &OSMESA_CONF(libgl), sizeof(OSMESA_CONF(libgl)), 0},
1249 	{ "LibOSMesa", String_Tag, &OSMESA_CONF(libosmesa), sizeof(OSMESA_CONF(libosmesa)), 0},
1250 	{ NULL , Error_Tag, NULL, 0, 0 }
1251 };
1252 
preset_osmesa()1253 static void preset_osmesa() {
1254 	OSMESA_CONF(channel_size) = 0;
1255 	safe_strncpy(OSMESA_CONF(libgl), DEFAULT_OPENGL, sizeof(OSMESA_CONF(libgl)));
1256 	safe_strncpy(OSMESA_CONF(libosmesa), DEFAULT_OSMESA, sizeof(OSMESA_CONF(libosmesa)));
1257 }
1258 
postload_osmesa()1259 static void postload_osmesa() {
1260 }
1261 
presave_osmesa()1262 static void presave_osmesa() {
1263 }
1264 
1265 /*************************************************************************/
1266 #define PARALLEL_CONF(x) bx_options.parallel.x
1267 
1268 struct Config_Tag parallel_conf[]={
1269 	{ "Type", String_Tag, &PARALLEL_CONF(type), sizeof(PARALLEL_CONF(type)), 0},
1270 	{ "File", String_Tag, &PARALLEL_CONF(file), sizeof(PARALLEL_CONF(file)), 0},
1271 	{ "Parport", String_Tag, &PARALLEL_CONF(parport), sizeof(PARALLEL_CONF(parport)), 0},
1272 	{ "Enabled", Bool_Tag, &PARALLEL_CONF(enabled), 0, 0},
1273 	{ NULL , Error_Tag, NULL, 0, 0 }
1274 };
1275 
preset_parallel()1276 static void preset_parallel() {
1277   safe_strncpy(PARALLEL_CONF(type), "file", sizeof(PARALLEL_CONF(type)));
1278   safe_strncpy(PARALLEL_CONF(file), "stderr", sizeof(PARALLEL_CONF(type)));
1279   safe_strncpy(PARALLEL_CONF(parport), "/dev/parport0", sizeof(PARALLEL_CONF(parport)));
1280 }
1281 
postload_parallel()1282 static void postload_parallel() {
1283 }
1284 
presave_parallel()1285 static void presave_parallel() {
1286 }
1287 /*************************************************************************/
1288 #define SERIAL_CONF(x) bx_options.serial.x
1289 
1290 struct Config_Tag serial_conf[]={
1291 	{ "Serport", String_Tag, &SERIAL_CONF(serport), sizeof(SERIAL_CONF(serport)), 0},
1292 	{ "Enabled", Bool_Tag, &SERIAL_CONF(enabled), 0, 0},
1293 	{ NULL , Error_Tag, NULL, 0, 0 }
1294 };
1295 
preset_serial()1296 static void preset_serial() {
1297   safe_strncpy(SERIAL_CONF(serport), DEFAULT_SERIAL, sizeof(SERIAL_CONF(serport)));
1298 }
1299 
postload_serial()1300 static void postload_serial() {
1301 }
1302 
presave_serial()1303 static void presave_serial() {
1304 }
1305 
1306 /*************************************************************************/
1307 #define NATFEAT_CONF(x) bx_options.natfeats.x
1308 
1309 struct Config_Tag natfeat_conf[]={
1310 	{ "CDROM", String_Tag, &NATFEAT_CONF(cdrom_driver), sizeof(NATFEAT_CONF(cdrom_driver)), 0},
1311 	{ "Vdi", String_Tag, &NATFEAT_CONF(vdi_driver), sizeof(NATFEAT_CONF(vdi_driver)), 0},
1312 	{ "HOSTEXEC", Bool_Tag, &NATFEAT_CONF(hostexec_enabled), 0, 0},
1313 	{ NULL , Error_Tag, NULL, 0, 0 }
1314 };
1315 
preset_natfeat()1316 static void preset_natfeat() {
1317   safe_strncpy(NATFEAT_CONF(cdrom_driver), "sdl", sizeof(NATFEAT_CONF(cdrom_driver)));
1318   safe_strncpy(NATFEAT_CONF(vdi_driver), "soft", sizeof(NATFEAT_CONF(vdi_driver)));
1319   NATFEAT_CONF(hostexec_enabled) = false;
1320 }
1321 
postload_natfeat()1322 static void postload_natfeat()
1323 {
1324 #ifndef ENABLE_OPENGL
1325   safe_strncpy(NATFEAT_CONF(vdi_driver), "soft", sizeof(NATFEAT_CONF(vdi_driver)));
1326 #endif
1327 }
1328 
presave_natfeat()1329 static void presave_natfeat() {
1330 }
1331 
1332 /*************************************************************************/
1333 #define NFVDI_CONF(x) bx_options.nfvdi.x
1334 
1335 struct Config_Tag nfvdi_conf[]={
1336 	{ "UseHostMouseCursor", Bool_Tag,  &NFVDI_CONF(use_host_mouse_cursor), 0, 0},
1337 	{ NULL , Error_Tag, NULL, 0, 0 }
1338 };
1339 
preset_nfvdi()1340 static void preset_nfvdi() {
1341 	NFVDI_CONF(use_host_mouse_cursor) = false;
1342 }
1343 
postload_nfvdi()1344 static void postload_nfvdi() {
1345 }
1346 
presave_nfvdi()1347 static void presave_nfvdi() {
1348 }
1349 
1350 /*************************************************************************/
1351 
1352 static char hotkeys[10][HOTKEYS_STRING_SIZE];
1353 struct Config_Tag hotkeys_conf[]={
1354 	{ "Setup", String_Tag, hotkeys[0], HOTKEYS_STRING_SIZE, 0},
1355 	{ "Quit", String_Tag, hotkeys[1], HOTKEYS_STRING_SIZE, 0},
1356 	{ "Reboot", String_Tag, hotkeys[2], HOTKEYS_STRING_SIZE, 0},
1357 	{ "ColdReboot", String_Tag, hotkeys[3], HOTKEYS_STRING_SIZE, 0},
1358 	{ "Ungrab", String_Tag, hotkeys[4], HOTKEYS_STRING_SIZE, 0},
1359 	{ "Debug", String_Tag, hotkeys[5], HOTKEYS_STRING_SIZE, 0},
1360 	{ "Screenshot", String_Tag, hotkeys[6], HOTKEYS_STRING_SIZE, 0},
1361 	{ "Fullscreen", String_Tag, hotkeys[7], HOTKEYS_STRING_SIZE, 0},
1362 	{ "Sound", String_Tag, hotkeys[8], HOTKEYS_STRING_SIZE, 0},
1363 	{ NULL , Error_Tag, NULL, 0, 0 }
1364 };
1365 
1366 typedef struct { char *string; bx_hotkey *keysym; } HOTKEYS_REL;
1367 
1368 HOTKEYS_REL hotkeys_rel[]={
1369 	{ hotkeys[0], &bx_options.hotkeys.setup },
1370 	{ hotkeys[1], &bx_options.hotkeys.quit },
1371 	{ hotkeys[2], &bx_options.hotkeys.warmreboot },
1372 	{ hotkeys[3], &bx_options.hotkeys.coldreboot },
1373 	{ hotkeys[4], &bx_options.hotkeys.ungrab },
1374 	{ hotkeys[5], &bx_options.hotkeys.debug },
1375 	{ hotkeys[6], &bx_options.hotkeys.screenshot },
1376 	{ hotkeys[7], &bx_options.hotkeys.fullscreen },
1377 	{ hotkeys[8], &bx_options.hotkeys.sound }
1378 };
1379 
preset_hotkeys()1380 static void preset_hotkeys()
1381 {
1382 	// default values
1383 #ifdef OS_darwin
1384 	strcpy(hotkeys[0], "LM+,");
1385 	strcpy(hotkeys[1], "LM+q");
1386 	strcpy(hotkeys[2], "LM+r");
1387 	strcpy(hotkeys[3], "LS+LM+r");
1388 	strcpy(hotkeys[4], "LM+Escape");
1389 	strcpy(hotkeys[5], "LM+d");
1390 	strcpy(hotkeys[6], "LM+s");
1391 	strcpy(hotkeys[7], "LM+f");
1392 	strcpy(hotkeys[8], "RM+s");
1393 #else
1394 	strcpy(hotkeys[0], "Pause");
1395 	strcpy(hotkeys[1], "LS+Pause");
1396 	strcpy(hotkeys[2], "LC+Pause");
1397 	strcpy(hotkeys[3], "LS+LC+Pause");
1398 	strcpy(hotkeys[4], "LS+LC+LA+Escape");
1399 	strcpy(hotkeys[5], "LA+Pause");
1400 	strcpy(hotkeys[6], "PrintScreen");
1401 	strcpy(hotkeys[7], "ScrollLock");
1402 	strcpy(hotkeys[8], "RA+s");
1403 #endif
1404 }
1405 
postload_hotkeys()1406 static void postload_hotkeys() {
1407 	// convert from string to pair of ints
1408 	for(uint16 i=0; i<sizeof(hotkeys_rel)/sizeof(hotkeys_rel[0]); i++) {
1409 		stringToKeysym(hotkeys_rel[i].keysym, hotkeys_rel[i].string);
1410 	}
1411 }
1412 
presave_hotkeys()1413 static void presave_hotkeys() {
1414 	// convert from pair of ints to string
1415 	for(uint16 i=0; i<sizeof(hotkeys_rel)/sizeof(hotkeys_rel[0]); i++) {
1416 		keysymToString(hotkeys_rel[i].string, hotkeys_rel[i].keysym);
1417 	}
1418 }
1419 
1420 /*************************************************************************/
1421 struct Config_Tag ikbd_conf[]={
1422 	{ "WheelEiffel", Bool_Tag, &bx_options.ikbd.wheel_eiffel, 0, 0},
1423 	{ "AltGr", Bool_Tag, &bx_options.ikbd.altgr, 0, 0},
1424 	{ NULL , Error_Tag, NULL, 0, 0 }
1425 };
1426 
preset_ikbd()1427 static void preset_ikbd()
1428 {
1429 	bx_options.ikbd.wheel_eiffel = false;
1430 	bx_options.ikbd.altgr = true;
1431 }
1432 
postload_ikbd()1433 static void postload_ikbd()
1434 {
1435 }
1436 
presave_ikbd()1437 static void presave_ikbd()
1438 {
1439 }
1440 
1441 /*************************************************************************/
1442 struct Config_Tag audio_conf[]={
1443 	{ "Frequency", Int_Tag, &bx_options.audio.freq, 0, 0},
1444 	{ "Channels", Int_Tag, &bx_options.audio.chans, 0, 0},
1445 	{ "Bits", Int_Tag, &bx_options.audio.bits, 0, 0},
1446 	{ "Samples", Int_Tag, &bx_options.audio.samples, 0, 0},
1447 	{ "Enabled", Bool_Tag, &bx_options.audio.enabled, 0, 0},
1448 	{ NULL , Error_Tag, NULL, 0, 0 }
1449 };
1450 
preset_audio()1451 static void preset_audio() {
1452   bx_options.audio.freq = 22050;
1453   bx_options.audio.chans = 2;
1454   bx_options.audio.bits = 16;
1455   bx_options.audio.samples = 1024;
1456   bx_options.audio.enabled = true;
1457 }
1458 
postload_audio()1459 static void postload_audio() {
1460 	if (host)
1461 		host->audio.Enable(bx_options.audio.enabled);
1462 }
1463 
presave_audio()1464 static void presave_audio() {
1465 }
1466 
1467 /*************************************************************************/
1468 struct Config_Tag joysticks_conf[]={
1469 	{ "Ikbd0", Int_Tag, &bx_options.joysticks.ikbd0, 0, 0},
1470 	{ "Ikbd1", Int_Tag, &bx_options.joysticks.ikbd1, 0, 0},
1471 	{ "JoypadA", Int_Tag, &bx_options.joysticks.joypada, 0, 0},
1472 	{ "JoypadAButtons", String_Tag, &bx_options.joysticks.joypada_mapping,
1473 		sizeof(bx_options.joysticks.joypada_mapping), 0},
1474 	{ "JoypadB", Int_Tag, &bx_options.joysticks.joypadb, 0, 0},
1475 	{ "JoypadBButtons", String_Tag, &bx_options.joysticks.joypadb_mapping,
1476 		sizeof(bx_options.joysticks.joypadb_mapping), 0},
1477 	{ NULL , Error_Tag, NULL, 0, 0 }
1478 };
1479 
preset_joysticks()1480 static void preset_joysticks() {
1481 	bx_options.joysticks.ikbd0 = -1;	/* This one is wired to mouse */
1482 	bx_options.joysticks.ikbd1 = 0;
1483 	bx_options.joysticks.joypada = -1;
1484 	bx_options.joysticks.joypadb = -1;
1485 	safe_strncpy(bx_options.joysticks.joypada_mapping,
1486 		"0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16",
1487 		sizeof(bx_options.joysticks.joypada_mapping));
1488 	safe_strncpy(bx_options.joysticks.joypadb_mapping,
1489 		"0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16",
1490 		sizeof(bx_options.joysticks.joypadb_mapping));
1491 }
1492 
postload_joysticks()1493 static void postload_joysticks() {
1494 }
1495 
presave_joysticks()1496 static void presave_joysticks() {
1497 }
1498 
1499 /*************************************************************************/
1500 
1501 struct Config_Tag cmdline_conf[]={
1502 	{ "IdeSwap", Bool_Tag, &ide_swap, 0, 0 },
1503 	{ "BootEmutos", Bool_Tag, &boot_emutos, 0, 0 },
1504 	{ "BootLilo", Bool_Tag, &boot_lilo, 0, 0 },
1505 	{ "HaltOnReboot", Bool_Tag, &halt_on_reboot, 0, 0 },
1506 	{ "ConfigFile", Path_Tag, config_file, sizeof(config_file), 0 },
1507 #ifdef SDL_GUI
1508 	{ "StartupGUI", Bool_Tag, &startupGUI, 0, 0 },
1509 #endif
1510 	{ NULL , Error_Tag, NULL, 0, 0 }
1511 };
1512 
1513 /*************************************************************************/
1514 static struct Config_Section const all_sections[] = {
1515 	{ "[GLOBAL]",     global_conf,   false, preset_global, postload_global, presave_global },
1516 	{ "[STARTUP]",    startup_conf,  false, preset_startup, postload_startup, presave_startup },
1517 	{ "[IKBD]",       ikbd_conf,     false, preset_ikbd, postload_ikbd, presave_ikbd },
1518 	{ "[HOTKEYS]",    hotkeys_conf,  false, preset_hotkeys, postload_hotkeys, presave_hotkeys },
1519 	{ "[JIT]",        jit_conf,      false, preset_jit, postload_jit, presave_jit },
1520 	{ "[VIDEO]",      video_conf,    false, preset_video, postload_video, presave_video },
1521 	{ "[TOS]",        tos_conf,      false, preset_tos, postload_tos, presave_tos },
1522 	{ "[IDE0]",       diskc_configs, false, preset_ide, postload_ide, presave_ide }, // beware of ide_swap
1523 	{ "[IDE1]",       diskd_configs, false, 0, 0, 0 },
1524 	  /* DISKS sections */
1525 	{ "[PARTITION0]", disk0_configs, false, preset_disk, postload_disk, presave_disk },
1526 	{ "[PARTITION1]", disk1_configs, true,  0, 0, 0 },
1527 	{ "[PARTITION2]", disk2_configs, true,  0, 0, 0 },
1528 	{ "[PARTITION3]", disk3_configs, true,  0, 0, 0 },
1529 	{ "[PARTITION4]", disk4_configs, true,  0, 0, 0 },
1530 	{ "[PARTITION5]", disk5_configs, true,  0, 0, 0 },
1531 	{ "[PARTITION6]", disk6_configs, true,  0, 0, 0 },
1532 	{ "[PARTITION7]", disk7_configs, true,  0, 0, 0 },
1533 	{ "[HOSTFS]",     arafs_conf,    false, preset_arafs, postload_arafs, presave_arafs },
1534 	{ "[OPENGL]",     opengl_conf,   false, preset_opengl, postload_opengl, presave_opengl },
1535 	  /* MAX_ETH sections */
1536 	{ "[ETH0]",       eth0_conf,     false, preset_ethernet, postload_ethernet, presave_ethernet },
1537 	{ "[ETH1]",       eth1_conf,     true,  0, 0, 0 },
1538 	{ "[ETH2]",       eth2_conf,     true,  0, 0, 0 },
1539 	{ "[ETH3]",       eth3_conf,     true,  0, 0, 0 },
1540 	{ "[LILO]",       lilo_conf,     false, preset_lilo, postload_lilo, presave_lilo },
1541 	{ "[MIDI]",       midi_conf,     false, preset_midi, postload_midi, presave_midi },
1542 	{ "[CDROMS]",     nfcdroms_conf, false, preset_nfcdroms, postload_nfcdroms, presave_nfcdroms },
1543 	{ "[AUTOZOOM]",   autozoom_conf, false, preset_autozoom, postload_autozoom, presave_autozoom },
1544 	{ "[NFOSMESA]",   osmesa_conf,   false, preset_osmesa, postload_osmesa, presave_osmesa },
1545 	{ "[PARALLEL]",   parallel_conf, false, preset_parallel, postload_parallel, presave_parallel },
1546 	{ "[SERIAL]",     serial_conf,   false, preset_serial, postload_serial, presave_serial },
1547 	{ "[NATFEATS]",   natfeat_conf,  false, preset_natfeat, postload_natfeat, presave_natfeat },
1548 	{ "[NFVDI]",      nfvdi_conf,    false, preset_nfvdi, postload_nfvdi, presave_nfvdi },
1549 	{ "[AUDIO]",      audio_conf,    false, preset_audio, postload_audio, presave_audio },
1550 	{ "[JOYSTICKS]",  joysticks_conf,false, preset_joysticks, postload_joysticks, presave_joysticks },
1551 	{ "cmdline",      cmdline_conf,  false, 0, 0, 0 },
1552 	{ 0, 0, false, 0, 0, 0 }
1553 };
1554 
getConfigSections(void)1555 const struct Config_Section *getConfigSections(void)
1556 {
1557 	return all_sections;
1558 }
1559 
1560 /*************************************************************************/
usage(int status)1561 static void usage (int status) {
1562   printf ("Usage: %s [OPTIONS]\n", program_name);
1563   printf ("\
1564 Options:\n\
1565   -a, --floppy NAME               floppy image file NAME\n\
1566   -e, --emutos                    boot EmuTOS\n\
1567   -N, --nomouse                   don't grab mouse at startup\n\
1568   -f, --fullscreen                start in fullscreen\n\
1569   -v, --refresh <X>               VIDEL refresh rate in VBL (default 2)\n\
1570   -r, --resolution <X>            boot in X color depth [1,2,4,8,16]\n\
1571   -m, --monitor <X>               attached monitor: 0 = VGA, 1 = TV\n\
1572   -c, --config FILE               read different configuration file\n\
1573   -s, --save                      save configuration file\n\
1574   -S, --swap-ide                  swap IDE drives\n\
1575   -P <X,Y> or <center>            set window position\n\
1576   -k, --locale <XY>               set NVRAM keyboard layout and language\n\
1577       --option section:key:value  set configuration value\n\
1578 ");
1579 #ifdef SDL_GUI
1580   printf("  -G, --gui                       open GUI at startup\n");
1581 #endif
1582 #if HOSTFS_SUPPORT
1583   printf("  -d, --disk CHAR:PATH[:]         HostFS mapping, e.g. d:/atari/d_drive\n");
1584 #endif
1585 #ifdef ENABLE_LILO
1586   printf("  -l, --lilo                      boot a linux kernel\n");
1587   printf("  -H, --halt                      linux kernel halts on reboot\n");
1588 #endif
1589 #ifndef FixedSizeFastRAM
1590   printf("  -F, --fastram SIZE              FastRAM size (in MB)\n");
1591 #endif
1592 #if FIXED_ADDRESSING
1593   printf("      --fixedmem OFFSET           use OFFSET for Atari memory (default: 0x%08x)\n", (unsigned int) fixed_memory_offset);
1594   printf("      --probe-fixed               try to figure out best value for above offset\n");
1595 #endif
1596 #ifdef DEBUGGER
1597   printf("  -D, --debug                     start debugger\n");
1598 #endif
1599   printf ("\
1600 \n\
1601   -h, --help                      display this help and exit\n\
1602   -V, --version                   output version information and exit\n\
1603 ");
1604   exit (status);
1605 }
1606 
preset_cfg()1607 static void preset_cfg() {
1608 	for (const struct Config_Section *section = all_sections; section->name; section++)
1609 	{
1610 		if (section->skip_if_empty)
1611 		{
1612 			/*
1613 			 * This is assumed in saveSettings().
1614 			 * Check this here because it is not called on startup.
1615 			 */
1616 			if (section->tags->type != String_Tag && section->tags->type != Path_Tag)
1617 			{
1618 				panicbug("type of first entry in config section %s not String or Path", section->name);
1619 				abort();
1620 			}
1621 		}
1622 		if (section->preset)
1623 			section->preset();
1624 	}
1625 }
1626 
postload_cfg()1627 static void postload_cfg() {
1628 	for (const struct Config_Section *section = all_sections; section->name; section++)
1629 		if (section->postload)
1630 			section->postload();
1631 }
1632 
presave_cfg()1633 static void presave_cfg() {
1634 	for (const struct Config_Section *section = all_sections; section->name; section++)
1635 		if (section->presave)
1636 			section->presave();
1637 }
1638 
print_version(void)1639 static void print_version(void)
1640 {
1641 	loadSettings(config_file);
1642 	// infoprint("%s\n", version_string);
1643 	infoprint("Configuration:");
1644 	infoprint("SDL (compiled)   : %d.%d.%d", SDL_MAJOR_VERSION, SDL_MINOR_VERSION, SDL_PATCHLEVEL);
1645 	SDL_version linked;
1646 	SDL_GetVersion(&linked);
1647 	infoprint("SDL (linked)     : %d.%d.%d", linked.major, linked.minor, linked.patch);
1648 	infoprint("CPU JIT compiler : %s%s", USE_JIT ? "enabled" : "disabled", USE_JIT ? (bx_options.jit.jit ? " (active)" : " (inactive)") : "");
1649 	infoprint("FPU JIT compiler : %s%s", USE_JIT_FPU ? "enabled" : "disabled", USE_JIT_FPU ? (bx_options.jit.jitfpu ? " (active)" : " (inactive)") : "");
1650 #if FIXED_ADDRESSING
1651 	if (fixed_memory_offset != FMEMORY)
1652 	infoprint("Addressing mode  : fixed (0x%08x; default: 0x%08x)", (unsigned int) fixed_memory_offset, FMEMORY);
1653 	else
1654 	infoprint("Addressing mode  : fixed (0x%08x)", (unsigned int) fixed_memory_offset);
1655 #else
1656 	infoprint("Addressing mode  : %s", DIRECT_ADDRESSING ? "direct" : "normal");
1657 #endif
1658 	infoprint("Memory check     : %s", MEMORY_CHECK);
1659 	infoprint("Full MMU         : %s", FULLMMU ? "enabled" : "disabled");
1660 	infoprint("FPU              : %s", USES_FPU_CORE);
1661 	infoprint("DSP              : %s", DSP_EMULATION ? "enabled" : "disabled");
1662 	infoprint("DSP disassembler : %s", DSP_DISASM ? "enabled" : "disabled");
1663 	infoprint("OpenGL support   : %s", ENABLE_OPENGL ? "enabled" : "disabled");
1664 	infoprint("Native features  : %s", PROVIDES_NATFEATS);
1665 }
1666 
early_cmdline_check(int argc,char ** argv)1667 static void early_cmdline_check(int argc, char **argv) {
1668 	for (int c = 0; c < argc; c++) {
1669 		char *p = argv[c];
1670 		if (strcmp(p, "-S") == 0  || strcmp(p, "--swap-ide") == 0)
1671 			ide_swap = true;
1672 
1673 		else if ((strcmp(p, "-c") == 0) || (strcmp(p, "--config") == 0)) {
1674 			if ((c + 1) < argc) {
1675 				setConfigFile(argv[c + 1]);
1676 			} else {
1677 				panicbug("config switch requires one parameter");
1678 				exit(EXIT_FAILURE);
1679 			}
1680 		} else if ((strcmp(p, "-h") == 0) || (strcmp(p, "--help") == 0)) {
1681 			usage(EXIT_SUCCESS);
1682 		} else if ((strcmp(p, "-V") == 0) || (strcmp(p, "--version") == 0)) {
1683 			print_version();
1684 			exit(EXIT_SUCCESS);
1685 #if FIXED_ADDRESSING
1686 		} else if ((strcmp(p, "--probe-fixed") == 0)) {
1687 			vm_probe_fixed();
1688 			exit(EXIT_SUCCESS);
1689 #endif
1690 		}
1691 	}
1692 }
1693 
process_cmdline(int argc,char ** argv)1694 static int process_cmdline(int argc, char **argv)
1695 {
1696 	int c;
1697 	while ((c = getopt_long (argc, argv,
1698 							 "a:" /* floppy image file */
1699 							 "e"  /* boot emutos */
1700 #ifdef ENABLE_LILO
1701 							 "l"  /* boot lilo */
1702 							 "H"  /* halt on reboot */
1703 #endif
1704 #ifdef DEBUGGER
1705 							 "D"  /* debugger */
1706 #endif
1707 #ifndef FixedSizeFastRAM
1708 							 "F:" /* FastRAM */
1709 #endif
1710 							 "N"  /* no mouse */
1711 							 "f"  /* fullscreen */
1712 							 "v:" /* VIDEL refresh */
1713 							 "r:" /* resolution */
1714 							 "m:" /* attached monitor */
1715 #if HOSTFS_SUPPORT
1716 							 "d:" /* filesystem assignment */
1717 #endif
1718 							 "s"  /* save config file */
1719 
1720 							 "c:" /* path to config file */
1721 #ifdef SDL_GUI
1722 							 "G"  /* GUI startup */
1723 #endif
1724 							 "P:" /* position of the window */
1725 							 "S"  /* swap IDE drives */
1726 							 "k:" /* keyboard layout */
1727 							 "h"  /* help */
1728 							 "V"  /* version */,
1729 							 long_options, (int *) 0)) != EOF) {
1730 		switch (c) {
1731 			case 'V':
1732 			case 'h':
1733 			case 'c':
1734 			case 'S':
1735 				/* processed in early_cmdline_check already */
1736 				break;
1737 #ifdef SDL_GUI
1738 			case 'G':
1739 				startupGUI = true;
1740 				break;
1741 #endif
1742 #ifdef DEBUGGER
1743 			case 'D':
1744 				bx_options.startup.debugger = true;
1745 				break;
1746 #endif
1747 
1748 			case 'e':
1749 				boot_emutos = true;
1750 				break;
1751 
1752 			case 'f':
1753 				bx_options.video.fullscreen = true;
1754 				break;
1755 
1756 #ifdef ENABLE_LILO
1757 			case 'l':
1758 				boot_lilo = true;
1759 				break;
1760 
1761 			case 'H':
1762 				halt_on_reboot = true;
1763 				break;
1764 #endif
1765 
1766 			case 'v':
1767 				bx_options.video.refresh = atoi(optarg);
1768 				break;
1769 
1770 			case 'N':
1771 				bx_options.startup.grabMouseAllowed = false;
1772 				break;
1773 
1774 			case 'm':
1775 				bx_options.video.monitor = atoi(optarg);
1776 				break;
1777 
1778 			case 'a':
1779 				if ((strlen(optarg)-1) > sizeof(bx_options.floppy.path))
1780 					panicbug("Floppy image filename longer than %u chars.", (unsigned)sizeof(bx_options.floppy.path));
1781 				safe_strncpy(bx_options.floppy.path, optarg, sizeof(bx_options.floppy.path));
1782 				break;
1783 
1784 			case 'r':
1785 				bx_options.video.boot_color_depth = atoi(optarg);
1786 				break;
1787 
1788 			case 'P':
1789 				safe_strncpy(bx_options.video.window_pos, optarg, sizeof(bx_options.video.window_pos));
1790 				break;
1791 
1792 #if HOSTFS_SUPPORT
1793 			case 'd':
1794 				if ( strlen(optarg) < 4 || optarg[1] != ':') {
1795 					panicbug("Not enough parameters for -d");
1796 					break;
1797 				}
1798 				// set the drive
1799 				{
1800 					int8 i = DriveFromLetter(optarg[0]);
1801 					if (i <= 0 || i >= HOSTFS_MAX_DRIVES) {
1802 						panicbug("Drive out of [A-Z] range for -d");
1803 						break;
1804 					}
1805 
1806 					safe_strncpy( bx_options.aranymfs.drive[i].configPath, optarg+2,
1807 								sizeof(bx_options.aranymfs.drive[i].configPath) );
1808 					// Note: tail colon processing (case sensitivity flag) is
1809 					// done later by calling postload_cfg.
1810 					// Just make sure postload_cfg is called after this.
1811 				}
1812 				break;
1813 #endif
1814 
1815 			case 's':
1816 				saveConfigFile = true;
1817 				break;
1818 
1819 #ifndef FixedSizeFastRAM
1820 			case 'F':
1821 				bx_options.fastram = atoi(optarg);
1822 				break;
1823 #endif
1824 
1825 			case 'k':
1826 				{
1827 					static struct {
1828 						char name[6];
1829 						nvram_t id;
1830 					} const countries[] = {
1831 						{ "us", COUNTRY_US }, { "en_US", COUNTRY_US },
1832 						{ "de", COUNTRY_DE }, { "de_DE", COUNTRY_DE },
1833 						{ "fr", COUNTRY_FR }, { "fr_FR", COUNTRY_FR },
1834 						{ "uk", COUNTRY_UK }, { "en_GB", COUNTRY_UK },
1835 						{ "es", COUNTRY_ES }, { "es_ES", COUNTRY_ES },
1836 						{ "it", COUNTRY_IT }, { "it_IT", COUNTRY_IT },
1837 						{ "se", COUNTRY_SE }, { "sv_SE", COUNTRY_SE },
1838 						{ "ch", COUNTRY_SF }, { "fr_CH", COUNTRY_SF },
1839 						{ "cd", COUNTRY_SG }, { "de_CH", COUNTRY_SG },
1840 						{ "tr", COUNTRY_TR }, { "tr_TR", COUNTRY_TR },
1841 						{ "fi", COUNTRY_FI }, { "fi_FI", COUNTRY_FI },
1842 						{ "no", COUNTRY_NO }, { "no_NO", COUNTRY_NO },
1843 						{ "dk", COUNTRY_DK }, { "da_DK", COUNTRY_DK },
1844 						{ "sa", COUNTRY_SA }, { "ar_SA", COUNTRY_SA },
1845 						{ "nl", COUNTRY_NL }, { "nl_NL", COUNTRY_NL },
1846 						{ "cz", COUNTRY_CZ }, { "cS_CZ", COUNTRY_CZ },
1847 						{ "hu", COUNTRY_HU }, { "hu_HU", COUNTRY_HU },
1848 						{ "pl", COUNTRY_PL }, { "pl_PL", COUNTRY_PL },
1849 						{ "lt", COUNTRY_PL }, { "lt_LT", COUNTRY_LT },
1850 						{ "ru", COUNTRY_RU }, { "ru_RU", COUNTRY_RU },
1851 						{ "ee", COUNTRY_EE }, { "et_EE", COUNTRY_EE },
1852 						{ "by", COUNTRY_BY }, { "be_BY", COUNTRY_BY },
1853 						{ "ua", COUNTRY_UA }, { "uk_UA", COUNTRY_UA },
1854 						{ "sk", COUNTRY_SK }, { "sk_SK", COUNTRY_SK },
1855 						{ "ro", COUNTRY_RO }, { "ro_RO", COUNTRY_RO },
1856 						{ "bg", COUNTRY_BG }, { "bg_BG", COUNTRY_BG },
1857 						{ "si", COUNTRY_SI }, { "sl_SI", COUNTRY_SI },
1858 						{ "hr", COUNTRY_HR }, { "hr_HR", COUNTRY_HR },
1859 						{ "rs", COUNTRY_RS }, { "sr_RS", COUNTRY_RS },
1860 						{ "me", COUNTRY_ME }, { "sr_ME", COUNTRY_ME },
1861 						{ "mk", COUNTRY_MK }, { "mk_MK", COUNTRY_MK },
1862 						{ "gr", COUNTRY_GR }, { "el_GR", COUNTRY_GR },
1863 						{ "lv", COUNTRY_LV }, { "lv_LV", COUNTRY_LV },
1864 						{ "il", COUNTRY_IL }, { "he_IL", COUNTRY_IL },
1865 						{ "za", COUNTRY_ZA }, { "af_ZA", COUNTRY_ZA }, /* ambigious language */
1866 						{ "pt", COUNTRY_PT }, { "pt_PT", COUNTRY_PT },
1867 						{ "be", COUNTRY_BE }, { "fr_BE", COUNTRY_BE },
1868 						{ "jp", COUNTRY_JP }, { "ja_JP", COUNTRY_JP },
1869 						{ "cn", COUNTRY_CN }, { "zh_CN", COUNTRY_CN },
1870 						{ "kr", COUNTRY_KR }, { "ko_KR", COUNTRY_KR },
1871 						{ "vn", COUNTRY_VN }, { "vi_VN", COUNTRY_VN },
1872 						{ "in", COUNTRY_IN }, { "ar_IN", COUNTRY_IN }, /* ambigious language */
1873 						{ "ir", COUNTRY_IR }, { "fa_IR", COUNTRY_IR },
1874 						{ "mn", COUNTRY_MN }, { "mn_MN", COUNTRY_MN },
1875 						{ "np", COUNTRY_NP }, { "ne_NP", COUNTRY_NP },
1876 						{ "la", COUNTRY_LA }, { "lo_LA", COUNTRY_LA },
1877 						{ "kh", COUNTRY_KH }, { "km_KH", COUNTRY_KH },
1878 						{ "id", COUNTRY_ID }, { "id_ID", COUNTRY_ID },
1879 						{ "bd", COUNTRY_BD }, { "bn_BD", COUNTRY_BD },
1880 					};
1881 					bx_options.tos.cookie_akp = -1;
1882 					for(unsigned i=0; i<sizeof(countries)/sizeof(countries[0]); i++) {
1883 						if (strcasecmp(optarg, countries[i].name) == 0) {
1884 							i = countries[i].id;
1885 							bx_options.tos.cookie_akp = i << 8 | i;
1886 							break;
1887 						}
1888 					}
1889 					if (bx_options.tos.cookie_akp == -1) {
1890 						char countrystr[(sizeof(countries)/sizeof(countries[0])) * 6 + 1];
1891 						*countrystr = '\0';
1892 						for(unsigned i=0; i<sizeof(countries)/sizeof(countries[0]); i++) {
1893 							strcat(countrystr, " ");
1894 							strcat(countrystr, countries[i].name);
1895 						}
1896 						panicbug("Error unknown country '%s', use one of: %s", optarg, countrystr);
1897 						exit(EXIT_FAILURE);
1898 					}
1899 				}
1900 				break;
1901 
1902 			case OPT_PROBE_FIXED:
1903 				/* processed in early_cmdline_check already */
1904 				break;
1905 
1906 #if FIXED_ADDRESSING
1907 			case OPT_FIXEDMEM_OFFSET:
1908 				bx_options.fixed_memory_offset = strtoul(optarg, NULL, 0);
1909 				break;
1910 #endif
1911 
1912 			case OPT_SET_OPTION:
1913 				{
1914 					char *section = optarg;
1915 					char *key = strchr(section, ':');
1916 					char *value;
1917 					if (key == NULL || (value = strchr(key + 1, ':')) == NULL)
1918 					{
1919 						if (strcmp(section, "help") == 0)
1920 						{
1921 							listConfigValues(true);
1922 							exit(EXIT_SUCCESS);
1923 						} else if (strcmp(section, "list") == 0)
1924 						{
1925 							listConfigValues(false);
1926 							exit(EXIT_SUCCESS);
1927 						} else
1928 						{
1929 							panicbug("wrong '--option' argument: must be section:key:value");
1930 							exit(EXIT_FAILURE);
1931 						}
1932 					} else
1933 					{
1934 						*key++ = '\0';
1935 						*value++ = '\0';
1936 						if (setConfigValue(section, key, value) == false)
1937 						{
1938 							/* exit(EXIT_FAILURE); */
1939 							bug("cannot set [%s]%s to %s (ignored)", section, key, value);
1940 						}
1941 					}
1942 				}
1943 				break;
1944 
1945 			default:
1946 				usage (EXIT_FAILURE);
1947 		}
1948 	}
1949 	return optind;
1950 }
1951 
1952 // append a filename to a path
addFilename(char * buffer,const char * file,unsigned int bufsize)1953 char *addFilename(char *buffer, const char *file, unsigned int bufsize)
1954 {
1955 	int dirlen = strlen(buffer);
1956 	if ((dirlen + 1 + strlen(file) + 1) < bufsize) {
1957 		if (dirlen > 0) {
1958 			char *ptrLast = buffer + dirlen - 1;
1959 			if (*ptrLast != '/' && *ptrLast != '\\')
1960 				strcat(buffer, DIRSEPARATOR);
1961 		}
1962 		strcat(buffer, file);
1963 	}
1964 	else {
1965 		panicbug("addFilename(\"%s\") - buffer too small!", file);
1966 		safe_strncpy(buffer, file, bufsize);	// at least the filename
1967 	}
1968 	strd2upath(buffer, buffer);
1969 	return buffer;
1970 }
1971 
1972 // build a complete path to an user-specific file
getConfFilename(const char * file,char * buffer,unsigned int bufsize)1973 char *getConfFilename(const char *file, char *buffer, unsigned int bufsize)
1974 {
1975 	Host::getConfFolder(buffer, bufsize);
1976 
1977 	// Does the folder exist?
1978 	struct stat buf;
1979 	if (stat(buffer, &buf) == -1) {
1980 		D(bug("Creating config folder '%s'", buffer));
1981 		Host::makeDir(buffer);
1982 	}
1983 
1984 	return addFilename(buffer, file, bufsize);
1985 }
1986 
1987 // build a complete path to system wide data file
getDataFilename(const char * file,char * buffer,unsigned int bufsize)1988 char *getDataFilename(const char *file, char *buffer, unsigned int bufsize)
1989 {
1990 	char *name = getConfFilename(file, buffer, bufsize);
1991 	struct stat buf;
1992 	if (stat(name, &buf) == -1)
1993 	{
1994 	  Host::getDataFolder(buffer, bufsize);
1995 	  name = addFilename(buffer, file, bufsize);
1996 	}
1997 	return name;
1998 }
1999 
decode_ini_file(const char * rcfile)2000 static bool decode_ini_file(const char *rcfile)
2001 {
2002 	// Does the config exist?
2003 	struct stat buf;
2004 	if (stat(rcfile, &buf) == -1) {
2005 		infoprint("Config file '%s' not found. It's been created with default values. Edit it to suit your needs.", rcfile);
2006 		saveConfigFile = true;
2007 #ifdef SDL_GUI
2008 		startupGUI = true;
2009 #endif
2010 		return false;
2011 	}
2012 
2013 	infoprint("Using config file: '%s'", rcfile);
2014 
2015 	bool verbose = false;
2016 
2017 	char home_folder[1024];
2018 	char data_folder[1024];
2019 	Host::getHomeFolder(home_folder, sizeof(home_folder));
2020 	Host::getDataFolder(data_folder, sizeof(data_folder));
2021 	ConfigOptions cfgopts(rcfile, home_folder, data_folder);
2022 
2023 	for (const struct Config_Section *section = all_sections; section->name; section++)
2024 	{
2025 		struct Config_Tag *conf = section->tags;
2026 
2027 		if (*section->name != '[') continue;
2028 		if (ide_swap)
2029 		{
2030 			if (conf == diskc_configs) conf = diskd_configs;
2031 			else if (conf == diskd_configs) conf = diskc_configs;
2032 		}
2033 		cfgopts.process_config(conf, section->name, verbose);
2034 	}
2035 
2036 	return true;
2037 }
2038 
loadSettings(const char * cfg_file)2039 bool loadSettings(const char *cfg_file) {
2040 	preset_cfg();
2041 	bool ret = decode_ini_file(cfg_file);
2042 	postload_cfg();
2043 	return ret;
2044 }
2045 
saveSettings(const char * fs)2046 bool saveSettings(const char *fs)
2047 {
2048 	presave_cfg();
2049 
2050 	char home_folder[1024];
2051 	char data_folder[1024];
2052 	Host::getHomeFolder(home_folder, sizeof(home_folder));
2053 	Host::getDataFolder(data_folder, sizeof(data_folder));
2054 	ConfigOptions cfgopts(fs, home_folder, data_folder);
2055 
2056 	bool first = true;
2057 	for (const struct Config_Section *section = all_sections; section->name; section++, first = false)
2058 	{
2059 		struct Config_Tag *conf = section->tags;
2060 
2061 		if (*section->name != '[') continue;
2062 		if (ide_swap)
2063 		{
2064 			if (conf == diskc_configs) conf = diskd_configs;
2065 			else if (conf == diskd_configs) conf = diskc_configs;
2066 		}
2067 		if (!section->skip_if_empty || strlen((const char *)conf->buf) != 0)
2068 			if (cfgopts.update_config(conf, section->name) < 0)
2069 			{
2070 				if (first)
2071 				{
2072 					panicbug("Error while writing the '%s' config file.", fs);
2073 					return false;
2074 				}
2075 			}
2076 	}
2077 
2078 	return true;
2079 }
2080 
2081 
2082 /*
2083  * set config variable by name
2084  * 'section_name' must be passed without brackets here
2085  */
setConfigValue(const char * section_name,const char * key,const char * value)2086 bool setConfigValue(const char *section_name, const char *key, const char *value)
2087 {
2088 	char home_folder[1024];
2089 	char data_folder[1024];
2090 	Host::getHomeFolder(home_folder, sizeof(home_folder));
2091 	Host::getDataFolder(data_folder, sizeof(data_folder));
2092 	ConfigOptions cfgopts(config_file, home_folder, data_folder);
2093 
2094 	int len = strlen(section_name);
2095 	for (const struct Config_Section *section = all_sections; section->name; section++)
2096 	{
2097 		struct Config_Tag *conf = section->tags;
2098 
2099 		if (*section->name != '[')
2100 			continue;
2101 		if (strncmp(section->name + 1, section_name, len) != 0 || section->name[len + 1] != ']')
2102 			continue;
2103 		if (ide_swap)
2104 		{
2105 			if (conf == diskc_configs) conf = diskd_configs;
2106 			else if (conf == diskd_configs) conf = diskc_configs;
2107 		}
2108 		for (; conf->code; conf++)
2109 		{
2110 			if (strcmp(conf->code, key) == 0)
2111 			{
2112 				bool ret = cfgopts.set_config_value(conf, value);
2113 				if (ret && section->postload)
2114 					section->postload();
2115 				return ret;
2116 			}
2117 		}
2118 		return false;
2119 	}
2120 
2121 	return false;
2122 }
2123 
2124 
listConfigValues(bool type)2125 void listConfigValues(bool type)
2126 {
2127 	char home_folder[1024];
2128 	char data_folder[1024];
2129 	Host::getHomeFolder(home_folder, sizeof(home_folder));
2130 	Host::getDataFolder(data_folder, sizeof(data_folder));
2131 	ConfigOptions cfgopts(config_file, home_folder, data_folder);
2132 
2133 	for (const struct Config_Section *section = all_sections; section->name; section++)
2134 	{
2135 		const char *name = section->name;
2136 		if (*name == '[')
2137 			name++;
2138 		const char *end = strchr(name, ']');
2139 		int len = (int)(end ? (end - name) : strlen(name));
2140 		char *section_name = strdup(name);
2141 		section_name[len] = '\0';
2142 
2143 		for (struct Config_Tag *conf = section->tags; conf->code; conf++)
2144 		{
2145 			if (ide_swap)
2146 			{
2147 				if (conf == diskc_configs) conf = diskd_configs;
2148 				else if (conf == diskd_configs) conf = diskc_configs;
2149 			}
2150 			char *value = cfgopts.get_config_value(conf, type);
2151 			printf("%s:%s:%s\n", section_name, conf->code, value ? value : "");
2152 
2153 		}
2154 		free(section_name);
2155 	}
2156 }
2157 
2158 
decode_switches(int argc,char ** argv)2159 bool decode_switches(int argc, char **argv)
2160 {
2161 	getConfFilename(ARANYMCONFIG, config_file, sizeof(config_file));
2162 
2163 	early_cmdline_check(argc, argv);
2164 	preset_cfg();
2165 	decode_ini_file(config_file);
2166 	process_cmdline(argc, argv);
2167 	postload_cfg();
2168 
2169 	if (saveConfigFile) {
2170 		D(bug("Storing configuration to file '%s'", config_file));
2171 		if (saveSettings(config_file))
2172 			loadSettings(config_file);
2173 	}
2174 
2175 	return true;
2176 }
2177 
getConfigFile()2178 const char *getConfigFile() {
2179 	return config_file;
2180 }
2181 
setConfigFile(const char * filename)2182 void setConfigFile(const char *filename)
2183 {
2184 	safe_strncpy(config_file, filename, sizeof(config_file));
2185 }
2186