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