1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
4 
5 #define _GNU_SOURCE 1
6 #include <uae/uae.h>
7 #ifdef USE_SDL
8 /* We must include SDL first before emu.h, so libfsemu's #definition of main
9  * is the current one (on Windows) when main is encountered further down. */
10 #include <SDL.h>
11 #endif
12 #ifdef MACOSX
13 #include <SDL.h>
14 #endif
15 #include <fs/base.h>
16 #include <fs/data.h>
17 #include <fs/emu.h>
18 #include <fs/emu/audio.h>
19 #include <fs/emu/path.h>
20 #include <fs/emu/video.h>
21 #include <fs/glib.h>
22 #include <fs/lazyness.h>
23 #include <fs/main.h>
24 #include <fs/i18n.h>
25 #include <fs/thread.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <locale.h>
31 #include "fs-uae.h"
32 #include "recording.h"
33 #include "plugins.h"
34 #include "options.h"
35 #include "paths.h"
36 #include "config-drives.h"
37 #ifdef WITH_CEF
38 #include <fs/emu/cef.h>
39 #endif
40 #include <fs/emu/hacks.h>
41 
42 #ifdef LINUX
43 #include "../../gamemode/lib/gamemode_client.h"
44 #endif
45 
46 static int fs_uae_argc;
47 static char **fs_uae_argv;
48 static int g_warn_about_missing_config_file;
49 
50 #define LOG_LINE "---------------------------------------------------------" \
51         "-------------------\n"
52 
change_port_device_mode(int data)53 static void change_port_device_mode(int data)
54 {
55     int modes = INPUTEVENT_AMIGA_JOYPORT_MODE_0_LAST -
56             INPUTEVENT_AMIGA_JOYPORT_MODE_0_NONE + 1;
57     int port = data / modes;
58     int mode = data % modes;
59     if (port >= 0 && port < FS_UAE_NUM_INPUT_PORTS) {
60         g_fs_uae_input_ports[port].mode = mode;
61         g_fs_uae_input_ports[port].new_mode = mode;
62         // The fifth port isn't an Amiga port, but rather a fake
63         // port used with custom input mapping only
64         if (port < 4) {
65             amiga_set_joystick_port_mode(port, mode);
66         }
67         fs_uae_reconfigure_input_ports_host();
68         fs_emu_menu_update_current();
69     }
70 }
71 
select_port_0_device(int data)72 static void select_port_0_device(int data)
73 {
74     printf("--> device index %d\n", data);
75     int port = 0;
76     if (data == 9) {
77         // 9 is currently a hack to indicate the local mouse
78         g_fs_uae_input_ports[port].mode = AMIGA_JOYPORT_MOUSE;
79         g_fs_uae_input_ports[port].new_mode = AMIGA_JOYPORT_MOUSE;
80         strcpy(g_fs_uae_input_ports[port].device, "MOUSE");
81         amiga_set_joystick_port_mode(port, AMIGA_JOYPORT_MOUSE);
82         // FIXME: not a warning, rather a notification
83         fs_emu_warning(_("Port 0: %s"), _("Mouse"));
84     }
85     else {
86         int count = 0;
87         int new_mode = AMIGA_JOYPORT_DJOY;
88         if (g_fs_uae_amiga_model == MODEL_CD32) {
89             new_mode = AMIGA_JOYPORT_CD32JOY;
90         }
91         fs_emu_input_device *devices = fs_emu_get_input_devices(&count);
92         if (data < count) {
93             g_fs_uae_input_ports[port].mode = new_mode;
94             g_fs_uae_input_ports[port].new_mode = new_mode;
95             uae_strlcpy(g_fs_uae_input_ports[port].device, devices[data].name,
96                         sizeof(g_fs_uae_input_ports[port].device));
97             amiga_set_joystick_port_mode(port, new_mode);
98             // FIXME: not a warning, rather a notification
99             fs_emu_warning(_("Port 0: %s"), devices[data].name);
100         }
101     }
102     fs_uae_reconfigure_input_ports_host();
103     fs_emu_menu_update_current();
104 
105     //fs_emu_get_input_devices()
106     //g_fs_uae_input_ports[port].mode = mode;
107     //amiga_set_joystick_port_mode(port,  mode);
108     //g_fs_uae_input_ports[port].new_mode = mode;
109     //fs_uae_reconfigure_input_ports_host();
110     //fs_emu_menu_update_current();
111 }
112 
113 int g_fs_uae_last_input_event = 0;
114 int g_fs_uae_last_input_event_state = 0;
115 int g_fs_uae_state_number = 0;
116 
fs_uae_process_input_event(int line,int action,int state,int playback)117 void fs_uae_process_input_event(int line, int action, int state, int playback)
118 {
119     static int first_time = 1;
120     if (first_time == 1) {
121         first_time = 0;
122         int load_state_number = fs_config_get_int("load_state");
123         if (load_state_number >= 1 && load_state_number <= 9) {
124             // FIXME: improvement, check if state file exists and show
125             // GUI warning if not...
126             fs_log("trying to load state number: %d\n", load_state_number);
127             amiga_send_input_event(
128                 INPUTEVENT_SPC_STATERESTORE1 - 1 + load_state_number, 1);
129         }
130     }
131 
132 #if 0
133     g_fs_uae_last_input_event = input_event;
134     g_fs_uae_last_input_event_state = state;
135     fs_emu_lua_run_handler("on_fs_uae_input_event");
136     // handler can modify input event
137     amiga_send_input_event(g_fs_uae_last_input_event,
138             g_fs_uae_last_input_event_state);
139 #endif
140 
141 #if 0
142     if (action == INPUTEVENT_KEY_RETURN) {
143         printf("FIXME: ignoring RETURN event for now\n");
144         return;
145     }
146 #endif
147 
148     if (action >= INPUTEVENT_AMIGA_JOYPORT_MODE_0_NONE &&
149             action < INPUTEVENT_AMIGA_JOYPORT_MODE_3_LAST) {
150         change_port_device_mode(
151                 action - INPUTEVENT_AMIGA_JOYPORT_MODE_0_NONE);
152         return;
153 
154     }
155     if (action >= INPUTEVENT_AMIGA_JOYPORT_0_DEVICE_0 &&
156             action < INPUTEVENT_AMIGA_JOYPORT_0_DEVICE_LAST) {
157         select_port_0_device(action - INPUTEVENT_AMIGA_JOYPORT_0_DEVICE_0);
158         return;
159     }
160     if (state && action >= INPUTEVENT_AMIGA_JOYPORT_0_AUTOFIRE &&
161             action <= INPUTEVENT_AMIGA_JOYPORT_3_AUTOFIRE) {
162         int port = action - INPUTEVENT_AMIGA_JOYPORT_0_AUTOFIRE;
163         if (g_fs_uae_input_ports[port].autofire_mode) {
164             g_fs_uae_input_ports[port].autofire_mode = 0;
165             amiga_set_joystick_port_autofire(port, 0);
166             fs_emu_warning(_("Auto-fire disabled for port %d"), port);
167         }
168         else {
169             g_fs_uae_input_ports[port].autofire_mode = 1;
170             amiga_set_joystick_port_autofire(port, 1);
171             fs_emu_warning(_("Auto-fire enabled for port %d"), port);
172         }
173         fs_emu_menu_update_current();
174         // this event must be passed on to the Amiga core
175     }
176 
177     int record_event = 1;
178     if (playback) {
179         record_event = 0;
180     }
181 
182     int load_state = 0;
183     int save_state = 0;
184     if (action >= INPUTEVENT_SPC_STATESAVE1 &&
185             action <= INPUTEVENT_SPC_STATESAVE9) {
186         save_state = action - INPUTEVENT_SPC_STATESAVE1 + 1;
187         g_fs_uae_state_number = save_state;
188     }
189 
190     if (action >= INPUTEVENT_SPC_STATERESTORE1 &&
191             action <= INPUTEVENT_SPC_STATERESTORE9) {
192         load_state = action - INPUTEVENT_SPC_STATERESTORE1 + 1;
193         g_fs_uae_state_number = load_state;
194     }
195 
196     if (load_state) {
197 #ifdef WITH_LUA
198         fs_log("run handler on_fs_uae_load_state\n");
199         fs_emu_lua_run_handler("on_fs_uae_load_state");
200 #endif
201         record_event = 0;
202     }
203     else if (save_state) {
204 #ifdef WITH_LUA
205         fs_log("run handler on_fs_uae_save_state\n");
206         fs_emu_lua_run_handler("on_fs_uae_save_state");
207 #endif
208         record_event = 0;
209     }
210 
211     if (record_event) {
212         fs_uae_record_input_event(line, action, state);
213     }
214     amiga_send_input_event(action, state);
215 
216     if (load_state) {
217 #ifdef WITH_LUA
218         fs_log("run handler on_fs_uae_load_state_done\n");
219         fs_emu_lua_run_handler("on_fs_uae_load_state_done");
220 #endif
221     }
222     else if (save_state) {
223 #ifdef WITH_LUA
224         fs_log("run handler on_fs_uae_save_state_done\n");
225         fs_emu_lua_run_handler("on_fs_uae_save_state_done");
226 #endif
227     }
228 }
229 
230 int g_fs_uae_frame = 0;
231 
input_handler_loop(int line)232 static int input_handler_loop(int line)
233 {
234     static int last_frame = -1;
235     if (g_fs_uae_frame != last_frame) {
236         // only run this for the first input handler loop per frame
237 #ifdef WITH_LUA
238         fs_emu_lua_run_handler("on_fs_uae_read_input");
239 #endif
240         last_frame = g_fs_uae_frame;
241     }
242 
243     // FIXME: Move to another place?
244     uae_clipboard_update();
245 
246     int action;
247     //int reconfigure_input = 0;
248     while ((action = fs_emu_get_input_event()) != 0) {
249         //printf("event_handler_loop received input action %d\n", action);
250         int istate = (action & 0x00ff0000) >> 16;
251         // force to -128 to 127 range
252         signed char state = (signed char) istate;
253         action = action & 0x0000ffff;
254         //amiga_keyboard_set_host_key(input_event, state);
255 
256         g_fs_uae_last_input_event = action;
257         g_fs_uae_last_input_event_state = state;
258 #ifdef WITH_LUA
259         fs_emu_lua_run_handler("on_fs_uae_input_event");
260 #endif
261 
262         // handler can modify input event
263         //action = g_fs_uae_last_input_event;
264         //state = g_fs_uae_last_input_event_state;
265         fs_uae_process_input_event(line, g_fs_uae_last_input_event,
266                 g_fs_uae_last_input_event_state, 0);
267     }
268 
269 #if 0
270     if (line == 0) {
271         int o = 300;
272         if (g_fs_uae_frame == o + 600) {
273             printf("Fake events!\n");
274             fs_uae_process_input_event(line, INPUTEVENT_MOUSE1_HORIZ, 50, 0);
275         }
276         if (g_fs_uae_frame == o + 650) {
277             fs_uae_process_input_event(line, INPUTEVENT_MOUSE1_VERT, 200, 0);
278         }
279         if (g_fs_uae_frame == o + 675) {
280             fs_uae_process_input_event(line, INPUTEVENT_MOUSE1_VERT, 30, 0);
281         }
282         if (g_fs_uae_frame == o + 700) {
283             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 1, 0);
284         }
285         if (g_fs_uae_frame == o + 710) {
286             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 0, 0);
287         }
288         if (g_fs_uae_frame == o + 800) {
289             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 1, 0);
290         }
291         if (g_fs_uae_frame == o + 810) {
292             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 0, 0);
293         }
294         if (g_fs_uae_frame == o + 900) {
295             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 1, 0);
296         }
297         if (g_fs_uae_frame == o + 910) {
298             fs_uae_process_input_event(line, INPUTEVENT_JOY1_FIRE_BUTTON, 0, 0);
299         }
300 #if 0
301         if (g_fs_uae_frame == 1000) {
302             fs_uae_process_input_event(line, INPUTEVENT_JOY1_2ND_BUTTON, 1, 0);
303         }
304         if (g_fs_uae_frame == 1050) {
305             fs_uae_process_input_event(line, INPUTEVENT_JOY1_2ND_BUTTON, 0, 0);
306         }
307 #endif
308     }
309 #endif
310 
311     int event, state;
312     while (fs_uae_get_recorded_input_event(g_fs_uae_frame, line, &event, &state)) {
313         fs_uae_process_input_event(line, event, state, 1);
314     }
315 
316     return 1;
317 }
318 
pause_throttle(void)319 static void pause_throttle(void)
320 {
321     /*
322     if (fs_emu_get_vblank_sync()) {
323         return;
324     }
325     */
326     fs_emu_msleep(5);
327 }
328 
event_handler(int line)329 static void event_handler(int line)
330 {
331     // printf("%d\n", line);
332     if (line >= 0) {
333         input_handler_loop(line);
334         return;
335     }
336     //static int busy = 0;
337     //static int idle = 0;
338     //static int64_t last_time = 0;
339     g_fs_uae_frame = g_fs_uae_frame + 1;
340 
341 #if 0
342     if (g_fs_uae_frame != amiga_get_vsync_counter()) {
343         printf("g_fs_uae_frame %d amiga_get_vsync_count %d\n", g_fs_uae_frame, amiga_get_vsync_counter());
344     }
345 #endif
346     //printf("event_handler frame=%d\n", frame);
347 
348     fs_uae_record_frame(g_fs_uae_frame);
349 
350     /*
351     int64_t t = fs_emu_monotonic_time();
352     if (last_time > 0) {
353         int dt = (t - last_time) / 1000;
354         printf("%d\n", dt);
355     }
356     */
357 
358     //fs_emu_lua_run_handler("on_fs_uae_frame_start");
359 
360     fs_emu_wait_for_frame(g_fs_uae_frame);
361     if (g_fs_uae_frame == 1) {
362         if (!fs_emu_netplay_enabled()) {
363             if (fs_config_true(OPTION_WARP_MODE)) {
364                 amiga_send_input_event(INPUTEVENT_SPC_WARP, 1);
365             }
366         }
367         /* We configure input ports after first frame are confirmed,
368          * because otherwise configure events would get lost if initially
369          * connected to the server (for net play game), but aborted connection
370          * before game started. */
371         fs_uae_reconfigure_input_ports_amiga();
372         /* Also configure input ports now (which also makes sure keyboard
373          * etc. is initialized) to ensure it is configured at least once. */
374         fs_uae_reconfigure_input_ports_host();
375     }
376 
377     if (fs_emu_is_quitting()) {
378         if (fs_emu_is_paused()) {
379             fs_emu_pause(0);
380         }
381         static int quit_called = 0;
382         if (quit_called == 0) {
383             fs_log("calling amiga_quit\n");
384             amiga_quit();
385             quit_called = 1;
386         }
387         //return;
388     }
389     while (fs_emu_is_paused()) {
390         /*
391         if (!event_handler_loop()) {
392             break;
393         }
394         */
395         pause_throttle();
396         if (fs_emu_is_quitting()) {
397             break;
398         }
399     }
400 
401     //last_time = fs_emu_monotonic_time();
402 
403 }
404 
405 char *g_fs_uae_disk_file_path = NULL;
406 char *g_fs_uae_config_file_path = NULL;
407 char *g_fs_uae_config_dir_path = NULL;
408 //GKeyFile *g_fs_uae_config = NULL;
409 
audio_callback_function(int type,int16_t * buffer,int size)410 static int audio_callback_function(int type, int16_t *buffer, int size)
411 {
412     if (type == 0) {
413         return fse_queue_audio_buffer(0, buffer, size);
414     } else if (type == 1) {
415         fse_set_audio_paused(0, true);
416         return 0;
417     } else if (type == 2) {
418         fse_set_audio_paused(0, false);
419         return 0;
420     } else if (type == 3) {
421         /* CD audio stream */
422         if (buffer == NULL) {
423             /* Check status of buffer number given by size. */
424             return fse_check_audio_buffer(1, size);
425         }
426         return fse_queue_audio_buffer(1, buffer, size);
427     }
428     return -1;
429 }
430 
fs_uae_load_rom_files(const char * path)431 void fs_uae_load_rom_files(const char *path)
432 {
433     fs_log("fs_uae_load_rom_files %s\n", path);
434     GDir *dir = g_dir_open(path, 0, NULL);
435     if (dir == NULL) {
436         fs_log("error opening dir\n");
437         return;
438     }
439 
440     // we include the rom key when generating the cache name for the
441     // kickstart cache file, so the cache will be regenerated if rom.key
442     // is replaced or removed/added.
443     char *key_path = g_build_filename(path, "rom.key", NULL);
444     GChecksum *rom_checksum = g_checksum_new(G_CHECKSUM_MD5);
445     FILE *f = g_fopen(key_path, "rb");
446     if (f != NULL) {
447         int64_t key_size = fs_path_get_size(key_path);
448         if (key_size > 0 && key_size < 1024 * 1024) {
449             guchar *key_data = malloc(key_size);
450             if (fread(key_data, key_size, 1, f) != 1) {
451                 free(key_data);
452             }
453             else {
454                 fs_log("read rom key file, size = %d\n", key_size);
455                 g_checksum_update(rom_checksum, key_data, key_size);
456             }
457         }
458         fclose(f);
459     }
460     g_free(key_path);
461 
462     amiga_add_key_dir(path);
463     const char *name = g_dir_read_name(dir);
464     while (name) {
465         char *lname = g_utf8_strdown(name, -1);
466         if (g_str_has_suffix(lname, ".rom")
467                 || g_str_has_suffix(lname, ".bin")) {
468             fs_log("found file \"%s\"\n", name);
469             char *full_path = g_build_filename(path, name, NULL);
470             //GChecksum *checksum = g_checksum_new(G_CHECKSUM_MD5);
471             GChecksum *checksum = g_checksum_copy(rom_checksum);
472             g_checksum_update(
473                 checksum, (guchar *) full_path, strlen(full_path));
474             const gchar *cache_name = g_checksum_get_string(checksum);
475             char* cache_path = g_build_filename(
476                 fs_uae_kickstarts_cache_dir(), cache_name, NULL);
477             amiga_add_rom_file(full_path, cache_path);
478             // check if amiga_add_rom_file needs to own full_path
479             //free(full_path);
480             if (cache_path != NULL) {
481                 free(cache_path);
482             }
483             g_checksum_free(checksum);
484         }
485         free(lname);
486         name = g_dir_read_name(dir);
487     }
488     g_dir_close(dir);
489 
490     if (rom_checksum != NULL) {
491         g_checksum_free(rom_checksum);
492     }
493     //exit(1);
494 }
495 
fs_uae_encode_path(const char * path)496 char *fs_uae_encode_path(const char *path)
497 {
498     // FIXME: libamiga now always accepts UTF-8, so this function is
499     // deprecated. Simply returning a duplicate now.
500     return g_strdup(path);
501 }
502 
fs_uae_decode_path(const char * path)503 char *fs_uae_decode_path(const char *path)
504 {
505     // FIXME: libamiga now always accepts UTF-8, so this function is
506     // deprecated. Simply returning a duplicate now.
507     return g_strdup(path);
508 }
509 
on_gui_message(const char * message)510 static void on_gui_message(const char *message)
511 {
512     printf("MESSAGE: %s\n", message);
513     fs_emu_warning("%s", message);
514 }
515 
on_init(void)516 static void on_init(void)
517 {
518     fs_log("\n");
519     fs_log(LOG_LINE);
520     fs_log("uae configuration\n");
521     fs_log(LOG_LINE);
522     fs_log("\n");
523 
524     amiga_set_gui_message_function(on_gui_message);
525 
526     //fs_uae_configure_amiga_model();
527     fs_uae_configure_amiga_hardware();
528     fs_uae_configure_floppies();
529     fs_uae_configure_hard_drives();
530     fs_uae_configure_cdrom();
531     fs_uae_configure_input();
532     fs_uae_configure_directories();
533 
534     if (fs_config_get_int("save_state_compression") == 0) {
535         amiga_set_save_state_compression(0);
536     }
537     else {
538         amiga_set_save_state_compression(1);
539     }
540 
541     if (fs_config_get_int("min_first_line_pal") != FS_CONFIG_NONE) {
542         amiga_set_min_first_line(fs_config_get_int("min_first_line_pal"), 0);
543     }
544     if (fs_config_get_int("min_first_line_ntsc") != FS_CONFIG_NONE) {
545         amiga_set_min_first_line(fs_config_get_int("min_first_line_ntsc"), 1);
546     }
547     if (fs_config_true(OPTION_CLIPBOARD_SHARING)) {
548         amiga_set_option("clipboard_sharing", "yes");
549     }
550 
551     /*
552     if (fs_emu_get_video_sync()) {
553         fs_log("fs_emu_get_video_sync returned true\n");
554         amiga_set_option("gfx_vsync", "true");
555     }
556     else {
557         fs_log("fs_emu_get_video_sync returned false\n");
558     }
559     if (fs_emu_netplay_enabled()) {
560         fs_log("netplay is enabled\n");
561         // make sure UAE does not sleep between frames, we must be able
562         // to control sleep times for net play
563         amiga_set_option("gfx_vsync", "true");
564     }
565     */
566 
567     /* With sound_auto set to true, UAE stops audio output if the amiga does
568      * not produce sound.  */
569     // amiga_set_option("sound_auto", "false");
570 
571     amiga_set_audio_frequency(fs_emu_audio_output_frequency());
572 
573     //amiga_set_audio_frequency(22050);
574 
575 
576     // set the input frequency to the output frequency, since we configured
577     // libamiga to output at the same frequency
578 
579     // FIXME: check the actual frequency libuae/libamiga outputs, seems
580     // to output at 44100 Hz even though currprefs.freq says 48000.
581     // fs_emu_set_audio_buffer_frequency(0, fs_emu_get_audio_frequency());
582 
583     //amiga_set_option("gfx_gamma", "40");
584 
585     fs_uae_set_uae_paths();
586     fs_uae_read_custom_uae_options(fs_uae_argc, fs_uae_argv);
587 
588     char *uae_file;
589 
590     uae_file = g_build_filename(fs_uae_logs_dir(), "LastConfig.uae", NULL);
591     if (fs_path_exists(uae_file)) {
592         g_unlink(uae_file);
593     }
594     g_free(uae_file);
595 
596     uae_file = g_build_filename(fs_uae_logs_dir(), "DebugConfig.uae", NULL);
597     if (fs_path_exists(uae_file)) {
598         g_unlink(uae_file);
599     }
600     g_free(uae_file);
601 
602     uae_file = g_build_filename(fs_uae_logs_dir(), "Debug.uae", NULL);
603     if (fs_path_exists(uae_file)) {
604         g_unlink(uae_file);
605     }
606     g_free(uae_file);
607 
608     uae_file = g_build_filename(fs_uae_logs_dir(), "debug.uae", NULL);
609     amiga_write_uae_config(uae_file);
610     g_free(uae_file);
611 
612     fs_log("\n");
613     fs_log(LOG_LINE);
614     fs_log("end of uae configuration\n");
615     fs_log(LOG_LINE);
616     fs_log("\n");
617 }
618 
pause_function(int pause)619 static void pause_function(int pause)
620 {
621     fs_log("pause_function %d\n", pause);
622     //uae_pause(pause);
623     amiga_pause(pause);
624 }
625 
load_config_file(void)626 static int load_config_file(void)
627 {
628     fs_log("load config file\n");
629     const char *msg = "checking config file %s\n";
630 
631     char *data;
632     int size;
633     if (fs_data_file_content("META-INF/Config.fs-uae", &data, &size) == 0) {
634         fs_ini_file *ini_file = fs_ini_file_open_data(data, size);
635         if (ini_file == NULL) {
636             fs_log("error loading config file\n");
637             return 1;
638         }
639         fs_config_parse_ini_file(ini_file, 0);
640         fs_ini_file_destroy(ini_file);
641         return 0;
642     }
643 
644     //g_fs_uae_config = g_key_file_new();
645     if (g_fs_uae_config_file_path == NULL) {
646         char *path = g_build_filename(fs_uae_exe_dir(), "Config.fs-uae",
647                 NULL);
648         fs_log(msg, path);
649         if (fs_path_exists(path)) {
650             g_fs_uae_config_file_path = path;
651         }
652         else {
653             free(path);
654         }
655     }
656 #ifdef MACOSX
657     if (g_fs_uae_config_file_path == NULL) {
658         char *path = g_build_filename(fs_uae_exe_dir(), "..", "..",
659                 "Config.fs-uae", NULL);
660         fs_log(msg, path);
661         if (fs_path_exists(path)) {
662             g_fs_uae_config_file_path = path;
663         }
664         else {
665             free(path);
666         }
667     }
668 #endif
669     if (g_fs_uae_config_file_path == NULL) {
670         fs_log(msg, "Config.fs-uae");
671         if (fs_path_exists("Config.fs-uae")) {
672             g_fs_uae_config_file_path = "Config.fs-uae";
673         }
674     }
675     if (g_fs_uae_config_file_path == NULL) {
676         fs_log(msg, "fs-uae.conf");
677         if (fs_path_exists("fs-uae.conf")) {
678             g_fs_uae_config_file_path = "fs-uae.conf";
679         }
680     }
681     if (g_fs_uae_config_file_path == NULL) {
682         char *path = g_build_filename(fse_user_config_dir(),
683                 "fs-uae", "fs-uae.conf", NULL);
684         fs_log(msg, path);
685         if (fs_path_exists(path)) {
686             g_fs_uae_config_file_path = path;
687         }
688         else {
689             free(path);
690         }
691     }
692     if (g_fs_uae_config_file_path == NULL) {
693         char *path = g_build_filename(fs_uae_configurations_dir(),
694                 "Default.fs-uae", NULL);
695         fs_log(msg, path);
696         if (fs_path_exists(path)) {
697             g_fs_uae_config_file_path = path;
698         }
699         else {
700             free(path);
701         }
702     }
703     if (g_fs_uae_config_file_path) {
704         fs_log("loading config from %s\n", g_fs_uae_config_file_path);
705         fs_config_read_file(g_fs_uae_config_file_path, 0);
706         g_fs_uae_config_dir_path = g_path_get_dirname(
707                 g_fs_uae_config_file_path);
708     }
709 #if 0
710     else {
711         if (fs_config_get_boolean("end_config") == 1) {
712             // do not warn in case end_config was specified via argv
713         }
714         else {
715             fs_log("No configuration file was found");
716             g_warn_about_missing_config_file = 1;
717         }
718     }
719 #endif
720 
721     char *path = g_build_filename(fs_uae_configurations_dir(),
722             "Host.fs-uae", NULL);
723     fs_log(msg, path);
724     if (fs_path_exists(path)) {
725         fs_config_read_file(path, 0);
726         free(path);
727     }
728 
729     return 0;
730 }
731 
log_to_libfsemu(const char * message)732 static void log_to_libfsemu(const char *message)
733 {
734     /* UAE logs some messages char-for-char, so we need to buffer logging
735      * here if we want to log with [UAE] prefix. */
736     // fs_log("[UAE] %s", message);
737     static bool initialized;
738     static bool ignore;
739     if (!initialized) {
740         initialized = true;
741         ignore = fs_config_false(OPTION_UAELOG);
742     }
743     if (!ignore) {
744         fs_log_string(message);
745     }
746 }
747 
main_function()748 static void main_function()
749 {
750     amiga_main();
751     fs_log("[CORE] Return from amiga_main\n");
752     fs_uae_write_recorded_session();
753 }
754 
755 #ifdef WINDOWS
756 // FIXME: move to fs_putenv
757 // int _putenv(const char *envstring);
758 #endif
759 
init_i18n(void)760 static void init_i18n(void)
761 {
762     // FIXME: language = 0 instead?
763     if (fs_config_get_boolean("localization") == 0) {
764         fs_log("[I18N ] Localization was forcefully disabled\n");
765         return;
766     }
767 
768     char *locale = setlocale(LC_MESSAGES, "");
769     if (locale) {
770         fs_log("[I18N] Locale is set to %s\n", locale);
771     } else {
772         fs_log("[I18N] Failed to set current locale\n");
773     }
774 
775     const char *language = fs_config_get_const_string("language");
776     if (language) {
777         fs_log("[I18N] Set environment LANGUAGE=%s\n", language);
778         char *env_str = g_strdup_printf("LANGUAGE=%s", language);
779 #ifdef WINDOWS
780         _putenv(env_str);
781 #else
782         putenv(env_str);
783 #endif
784         /* Do not free env_str, it's put directly in the environment. */
785     }
786 
787 #ifndef ANDROID
788     textdomain("fs-uae");
789 
790     char executable_dir[FS_PATH_MAX];
791     fs_get_application_exe_dir(executable_dir, FS_PATH_MAX);
792     char *locale_base = g_build_filename(
793         executable_dir, "..", "..", "Data", "Locale", NULL);
794     if (g_file_test(locale_base, G_FILE_TEST_IS_DIR)) {
795         fs_log("[I18N] Using locale dir \"%s\"\n", locale_base);
796         bindtextdomain("fs-uae", locale_base);
797         free(locale_base);
798     } else {
799         char *path = fs_get_data_file("fs-uae/share-dir");
800         if (path) {
801             fs_log("[I18N] Using data dir \"%s\"\n", path);
802             /* Remove trailing "fs-uae/share-dir" from the returned path. */
803             int len = strlen(path);
804             if (len > 16) {
805                 path[len - 16] = '\0';
806             }
807             char *locale_base = g_build_filename(path, "locale", NULL);
808             fs_log("[I18N] Using locale dir \"%s\"\n", locale_base);
809             bindtextdomain("fs-uae", locale_base);
810             free(locale_base);
811             free(path);
812         }
813     }
814     bind_textdomain_codeset("fs-uae", "UTF-8");
815 #endif
816 }
817 
led_function(int led,int state)818 static void led_function(int led, int state)
819 {
820     /* floppy led status is custom overlay 0..3 */
821 #if 0
822     if (led >= 0) {
823         printf("led %d state %d\n", led, state);
824     }
825 #endif
826     fs_emu_set_custom_overlay_state(led, state);
827 }
828 
on_update_leds(void * data)829 static void on_update_leds(void *data)
830 {
831     amiga_led_data *leds = (amiga_led_data *) data;
832     for (int i = 0; i < 4; i++) {
833         int led = 12; // df0_d1
834         led = led + i * 2;
835         fs_emu_set_custom_overlay_state(led + 0, leds->df_t1[i]);
836         fs_emu_set_custom_overlay_state(led + 1, leds->df_t0[i]);
837     }
838 }
839 
840 static unsigned int whdload_quit_key = 0;
841 static int64_t whdload_quit_time = 0;
842 
fs_emu_send_whdload_quit_key(int whdload_quit_key)843 static void fs_emu_send_whdload_quit_key(int whdload_quit_key) {
844     fs_log("Find input event for amiga key %d\n", whdload_quit_key);
845     int input_event = amiga_find_input_event_for_key(whdload_quit_key);
846     fs_log("Found input event %d for amiga key %d\n", input_event, whdload_quit_key);
847     if (input_event) {
848         fs_log("Sending WHDLoad quit key input");
849         fs_emu_queue_action(input_event, 1);
850     }
851 }
852 
quit_function()853 static int quit_function()
854 {
855     fs_log("quit_function\n");
856     if (whdload_quit_key) {
857         if (whdload_quit_time > 0) {
858             int64_t diff = fs_ml_monotonic_time() - whdload_quit_time;
859             if (diff < 0.1 * 1000000) {
860                 // Duplicate SDL_QUIT event?
861                 return 0;
862             }
863             // Press quit twice within one second to force quit
864             if (diff < 1.0 * 1000000) {
865                 return 1;
866             }
867         }
868         fs_log("NOT QUITING\n");
869         if (whdload_quit_time == 0) {
870             // Only show this message once
871             fs_emu_warning(
872                 "Sent WHDLoad quit key ($%02X) to exit gracefully",
873                 whdload_quit_key
874             );
875         } else {
876             fs_emu_warning("Press Quit twice to force quit");
877         }
878         fs_emu_send_whdload_quit_key(whdload_quit_key);
879         whdload_quit_time = fs_ml_monotonic_time();
880         return 0;
881     }
882     return 1;
883 }
884 
media_function(int drive,const char * path)885 static void media_function(int drive, const char *path)
886 {
887     // media insertion status is custom overlay 4..7
888     fs_emu_set_custom_overlay_state(4 + drive, path && path[0]);
889 }
890 
891 int ManyMouse_Init(void);
892 void ManyMouse_Quit(void);
893 const char *ManyMouse_DeviceName(unsigned int index);
894 
list_joysticks()895 static void list_joysticks()
896 {
897     printf("# FS-UAE %s\n", PACKAGE_VERSION);
898     printf("# listing keyboards\n");
899     printf("K: Keyboard\n");
900     printf("# listing mice\n");
901     printf("M: Mouse\n");
902     int count = ManyMouse_Init();
903     if (count >= 0) {
904         for (int i = 0; i < count; i++) {
905             const char *name = ManyMouse_DeviceName(i);
906             if (name[0] == 0 || strcasecmp(name, "mouse") == 0) {
907                 printf("M: Unnamed Mouse\n");
908             }
909             else {
910                 printf("M: %s\n", ManyMouse_DeviceName(i));
911             }
912         }
913         ManyMouse_Quit();
914     }
915 
916     printf("# listing joysticks\n");
917 #ifdef USE_SDL
918     if (SDL_Init(SDL_INIT_JOYSTICK ) < 0) {
919         printf("# SDL_Init(SDL_INIT_JOYSTICK ) < 0\n");
920         return;
921     }
922     printf("# SDL_NumJoysticks(): %d\n", SDL_NumJoysticks());
923     for(int i = 0; i < SDL_NumJoysticks(); i++) {
924         if (SDL_JoystickName(i)[0] == '\0') {
925             printf("J: Unnamed\n");
926         }
927         else {
928             printf("J: %s\n", SDL_JoystickName(i));
929         }
930     }
931 #else
932     printf("# USE_SDL is not defined\n");
933 #endif
934     printf("# listing joysticks done\n");
935 }
936 
937 extern int disk_debug_logging;
938 extern int g_frame_debug_logging;
939 extern int g_fsdb_debug;
940 extern int g_random_debug_logging;
941 extern int inputdevice_logging;
942 
configure_logging(const char * logstr)943 static void configure_logging(const char *logstr)
944 {
945     if (fs_config_get_int(OPTION_LOG_BSDSOCKET) == 1) {
946         log_bsd = 1;
947     }
948 
949     if (!logstr) {
950         fs_log("configure logging: none\n");
951         return;
952     }
953     fs_log("configure logging: %s\n", logstr);
954     int all = strstr(logstr, "all") != 0;
955     int uae_all = all || strstr(logstr, "uae") != 0;
956     if (uae_all || strstr(logstr, "uae_disk")) {
957         disk_debug_logging = 2;
958     }
959     if (uae_all || strstr(logstr, "uae_rand")) {
960         g_random_debug_logging = 2;
961     }
962     if (uae_all || strstr(logstr, "uae_input")) {
963         inputdevice_logging = 0xffff;
964     }
965     if (uae_all || strstr(logstr, "uae_fs")) {
966         g_fsdb_debug = 1;
967     }
968     if (uae_all || strstr(logstr, "uae_frame")) {
969         g_frame_debug_logging = 1;
970     }
971 }
972 
cleanup_old_file(const char * path)973 static void cleanup_old_file(const char *path)
974 {
975     char *p = fs_uae_expand_path(path);
976     if (fs_path_exists(p)) {
977         if (fs_path_is_dir(p)) {
978             fs_log("trying to remove old directory %s\n", p);
979             g_rmdir(p);
980         }
981         else {
982             fs_log("trying to remove old file %s\n", p);
983             g_unlink(p);
984         }
985     }
986     free(p);
987 }
988 
cleanup_old_files()989 static void cleanup_old_files()
990 {
991     // Logs are now stored in $BASE/Cache/Logs by default
992     cleanup_old_file("$BASE/Logs/FS-UAE.log");
993     cleanup_old_file("$BASE/Logs/FS-UAE.log.txt");
994     cleanup_old_file("$BASE/Logs/DebugConfig.uae");
995     cleanup_old_file("$BASE/Logs/Launcher.log.txt");
996     cleanup_old_file("$BASE/Logs/Synchronization.log");
997     // try to remove the dir - if it now is empty
998     cleanup_old_file("$BASE/Logs");
999 }
1000 
check_extension(const char * path,const char * ext)1001 static bool check_extension(const char *path, const char *ext)
1002 {
1003     if (path == NULL) {
1004         return false;
1005     }
1006     gchar* path_lower = g_ascii_strdown(path, -1);
1007     bool result = g_str_has_suffix(path_lower, ext);
1008     g_free(path_lower);
1009     return result;
1010 }
1011 
1012 #ifdef LINUX
check_linux_cpu_governor()1013 static void check_linux_cpu_governor()
1014 {
1015     gchar *governor;
1016     if (!g_file_get_contents(
1017             "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor",
1018             &governor, NULL, NULL)) {
1019         return;
1020     }
1021     g_strstrip(governor);
1022     fs_log("CPU scaling governor: '%s'\n", governor);
1023     if (fs_config_get_boolean(OPTION_GOVERNOR_WARNING) == 0) {
1024         return;
1025     }
1026     if (strcmp(governor, "performance") != 0) {
1027         fs_emu_warning(
1028             _("CPU scaling governor is '%s', not '%s'"),
1029             governor,
1030             "performance"
1031         );
1032         fs_emu_warning(_("Emulation frame rate may suffer"));
1033     }
1034     g_free(governor);
1035 }
1036 #endif
1037 
1038 static const char *overlay_names[] = {
1039     "df0_led",     // 0
1040     "df1_led",     // 1
1041     "df2_led",     // 2
1042     "df3_led",     // 3
1043     "df0_disk",    // 4
1044     "df1_disk",    // 5
1045     "df2_disk",    // 6
1046     "df3_disk",    // 7
1047     "power_led",   // 8
1048     "hd_led",      // 9
1049     "cd_led",      // 10
1050     "md_led",      // 11
1051 
1052     "df0_d1",      // 12
1053     "df0_d0",
1054     "df1_d1",
1055     "df1_d0",
1056     "df2_d1",
1057     "df2_d0",
1058     "df3_d1",
1059     "df3_d0",
1060     NULL,
1061 };
1062 
1063 #if defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
1064 #define ARCH_NAME_2 "x86-64"
1065 #elif defined(__i386__) || defined (_M_IX86)
1066 #define ARCH_NAME_2 "x86"
1067 #elif defined(__ppc__)
1068 #define ARCH_NAME_2 "PPC"
1069 #elif defined(__arm__)
1070 #define ARCH_NAME_2 "ARM"
1071 #else
1072 #define ARCH_NAME_2 "?"
1073 #endif
1074 
1075 #define COPYRIGHT_NOTICE "FS-UAE %s (Built for %s %s)\n" \
1076 "Copyright 1995-2002 Bernd Schmidt, 1999-2017 Toni Wilen,\n" \
1077 "2003-2007 Richard Drummond, 2006-2011 Mustafa 'GnoStiC' Tufan,\n" \
1078 "2011-2017 Frode Solheim, and contributors.\n" \
1079 "\n" \
1080 "This is free software; see the file COPYING for copying conditions. There\n" \
1081 "is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR\n" \
1082 "PURPOSE. See the README for more copyright info, and the source code for\n" \
1083 "a full list of contributors\n\n"
1084 
1085 #define EXTRA_HELP_TEXT "" \
1086 "Documentation is available at http://fs-uae.net/documentation\n" \
1087 "(See http://fs-uae.net/options for a list of configuration options)\n" \
1088 "\n"
1089 
1090 FILE *g_state_log_file = NULL;
1091 
main(int argc,char * argv[])1092 int main(int argc, char *argv[])
1093 {
1094     fs_uae_argc = argc;
1095     fs_uae_argv = argv;
1096     fs_set_argv(argc, argv);
1097 
1098 #ifdef WITH_CEF
1099     cef_init(argc, argv);
1100 #endif
1101 
1102     char **arg;
1103     arg = argv + 1;
1104     while (arg && *arg) {
1105         if (strcmp(*arg, "--list-joysticks") == 0) {
1106             list_joysticks();
1107             exit(0);
1108         } else if (strcmp(*arg, "--list-devices") == 0) {
1109             list_joysticks();
1110             exit(0);
1111         } else if (strcmp(*arg, "--version") == 0) {
1112             printf("%s\n", PACKAGE_VERSION);
1113             exit(0);
1114         } else if (strcmp(*arg, "--help") == 0) {
1115             printf(COPYRIGHT_NOTICE, PACKAGE_VERSION, OS_NAME_2, ARCH_NAME_2);
1116             printf(EXTRA_HELP_TEXT);
1117             exit(0);
1118         }
1119         arg++;
1120     }
1121 
1122     fs_init();
1123     int error = fs_data_init("fs-uae", "fs-uae.dat");
1124     if (error) {
1125         printf("WARNING: error (%d) loading fs-uae.dat\n", error);
1126     }
1127 
1128     fs_set_prgname("fs-uae");
1129     fs_set_application_name("Amiga Emulator");
1130 
1131     amiga_set_log_function(log_to_libfsemu);
1132 
1133     //result = parse_options(argc, argv);
1134 
1135     printf(COPYRIGHT_NOTICE, PACKAGE_VERSION, OS_NAME_2, ARCH_NAME_2);
1136     fs_log(COPYRIGHT_NOTICE, PACKAGE_VERSION, OS_NAME_2, ARCH_NAME_2);
1137 
1138     char *current_dir = g_get_current_dir();
1139     fs_log("current directory is %s\n", current_dir);
1140     g_free(current_dir);
1141 
1142     amiga_init();
1143 
1144 #ifdef MACOSX
1145     /* Can be overriden via environment variable (or launcher setting):
1146      *  SDL_VIDEO_MAC_FULLSCREEN_SPACES = 1 */
1147     SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "0");
1148 
1149     SDL_Init(SDL_INIT_EVERYTHING);
1150     SDL_PumpEvents();
1151     SDL_Event event;
1152     fs_log("OS X: Check for pending SDL_DROPFILE event\n");
1153     while (SDL_PollEvent(&event)) {
1154         fs_log("Got SDL event 0x%x\n", event.type);
1155         if (event.type == SDL_DROPFILE) {
1156             if (event.drop.file != NULL) {
1157                 g_fs_uae_config_file_path = strdup(event.drop.file);
1158             }
1159             SDL_free(event.drop.file);
1160         }
1161     }
1162 #endif
1163 
1164     // skip first entry
1165     arg = argv + 1;
1166     if (g_fs_uae_config_file_path == NULL) {
1167         while (arg && *arg) {
1168             const gchar *test_path = *arg;
1169             if (test_path && fs_path_exists(test_path)) {
1170                 if (check_extension(test_path, ".fs-uae")) {
1171                     g_fs_uae_config_file_path = g_strdup(test_path);
1172                 } else if (check_extension(test_path, ".conf")) {
1173                     g_fs_uae_config_file_path = g_strdup(test_path);
1174                 } else if (check_extension(test_path, ".adf")) {
1175                     g_fs_uae_disk_file_path = g_strdup(test_path);
1176                 } else if (check_extension(test_path, ".ipf")) {
1177                     g_fs_uae_disk_file_path = g_strdup(test_path);
1178                 } else if (check_extension(test_path, ".dms")) {
1179                     g_fs_uae_disk_file_path = g_strdup(test_path);
1180                 }
1181             }
1182             arg++;
1183         }
1184     }
1185 
1186     /* Parse options first, in case base_dir, logging  options etc is
1187      * specified on the command line. */
1188     fs_config_parse_options(argc - 1, argv + 1);
1189 
1190     fs_log("\n");
1191     fs_log(LOG_LINE);
1192     fs_log("libfsemu init\n");
1193     fs_log(LOG_LINE);
1194     fs_log("\n");
1195 
1196     fs_emu_path_set_expand_function(fs_uae_expand_path);
1197 
1198     fs_emu_init_overlays(overlay_names);
1199     fse_init_early();
1200 
1201     /* Then load the config file and set data dir */
1202     load_config_file();
1203     fs_set_data_dir(fs_uae_data_dir());
1204 
1205     init_i18n();
1206 
1207     if (g_fs_uae_disk_file_path) {
1208         fs_config_set_string(OPTION_FLOPPY_DRIVE_0, g_fs_uae_disk_file_path);
1209         g_warn_about_missing_config_file = 0;
1210     }
1211 
1212     if (g_warn_about_missing_config_file) {
1213         fs_emu_warning(_("No configuration file was found"));
1214     }
1215 #if 0
1216     const char *expect_version = fs_config_get_const_string(
1217                 OPTION_EXPECT_VERSION);
1218     if (expect_version && strcmp(expect_version, PACKAGE_VERSION) != 0) {
1219         fs_emu_warning(_("Expected FS-UAE version %s, got %s"),
1220                        expect_version, PACKAGE_VERSION);
1221     }
1222 #endif
1223 
1224 #ifdef LINUX
1225     if (fs_config_get_boolean(OPTION_GAME_MODE) != 0) {
1226         if (gamemode_request_start() < 0) {
1227             fs_log("GameMode: Request failed: %s\n", gamemode_error_string());
1228         } else {
1229             fs_log("GameMode: Enabled game mode\n");
1230         }
1231     }
1232     check_linux_cpu_governor();
1233 #endif
1234 
1235     fs_log("\n");
1236     fs_log(LOG_LINE);
1237     fs_log("fs-uae init\n");
1238     fs_log(LOG_LINE);
1239     fs_log("\n");
1240 
1241     configure_logging(fs_config_get_const_string("log"));
1242 
1243     fs_log("[GLIB] Version %d.%d.%d (Compiled against %d.%d.%d)\n",
1244            glib_major_version, glib_minor_version, glib_micro_version,
1245            GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
1246 #if 0
1247     fs_log("[GLIB] Using system malloc: %s\n",
1248            g_mem_is_system_malloc() ? "Yes" : "No");
1249 #endif
1250 
1251     fs_emu_set_state_check_function(amiga_get_state_checksum);
1252     fs_emu_set_rand_check_function(amiga_get_rand_checksum);
1253     fs_emu_set_quit_function(quit_function);
1254 
1255     // force creation of some recommended default directories
1256     fs_uae_kickstarts_dir();
1257     fs_uae_configurations_dir();
1258     fs_uae_init_path_resolver();
1259 
1260     fs_uae_plugins_init();
1261 
1262     // must be called early, before fs_emu_init -affects video output
1263     fs_uae_configure_amiga_model();
1264 
1265     // force creation of state directories
1266     //fs_uae_flash_memory_dir();
1267     //fs_uae_save_states_dir();
1268     //fs_uae_floppy_overlays_dir();
1269     fs_uae_state_dir();
1270 
1271     const char *controllers_dir = fs_uae_controllers_dir();
1272     if (controllers_dir) {
1273         fs_emu_set_controllers_dir(controllers_dir);
1274     }
1275     const char *logs_dir = fs_uae_logs_dir();
1276     if (logs_dir) {
1277         char *log_file;
1278 
1279         log_file = g_build_filename(logs_dir, "FS-UAE.log", NULL);
1280         if (fs_path_exists(log_file)) {
1281             g_unlink(log_file);
1282         }
1283         g_free(log_file);
1284 
1285         log_file = g_build_filename(logs_dir, "FS-UAE.log.txt", NULL);
1286         if (fs_path_exists(log_file)) {
1287             g_unlink(log_file);
1288         }
1289         g_free(log_file);
1290 
1291         log_file = g_build_filename(logs_dir, "Emulator.log.txt", NULL);
1292         if (fs_path_exists(log_file)) {
1293             g_unlink(log_file);
1294         }
1295         g_free(log_file);
1296 
1297         log_file = g_build_filename(logs_dir, "fs-uae.log.txt", NULL);
1298         fs_config_set_log_file(log_file);
1299         g_free(log_file);
1300     }
1301 
1302     fs_config_set_string_if_unset("themes_dir", fs_uae_themes_dir());
1303 
1304     fs_emu_set_pause_function(pause_function);
1305 
1306     //fs_uae_init_input();
1307     fse_init(FS_EMU_INIT_EVERYTHING);
1308 
1309     // we initialize the recording module either it is used or not, so it
1310     // can delete state-specific recordings (if necessary) when states are
1311     // saved
1312     fs_uae_init_recording();
1313 
1314     int deterministic_mode = 0;
1315     const char* record_file = fs_config_get_const_string("record");
1316     if (record_file) {
1317         fs_log("record file specified: %s, forcing deterministic mode\n",
1318             record_file);
1319         deterministic_mode = 1;
1320         fs_uae_enable_recording(record_file);
1321     } else {
1322         fs_log("not running in record mode\n");
1323     }
1324     if (fs_emu_netplay_enabled() ||
1325             fs_config_get_boolean(OPTION_DETERMINISTIC) == 1) {
1326         deterministic_mode = 1;
1327     }
1328     if (deterministic_mode) {
1329         amiga_set_deterministic_mode();
1330     }
1331 
1332     if (logs_dir) {
1333         if (fs_emu_netplay_enabled()) {
1334             char *sync_log_file = g_build_filename(logs_dir,
1335                     "Synchronization.log", NULL);
1336             amiga_set_synchronization_log_file(sync_log_file);
1337             free(sync_log_file);
1338         }
1339     }
1340 
1341 #if 1 // def FSE_DRIVERS
1342     fse_audio_stream_options **options = fs_emu_audio_alloc_stream_options(2);
1343     options[0]->frequency = fs_emu_audio_output_frequency();
1344     /* 12 * 2352 is CDDA_BUFFERS * 2352 (blkdev_cdimage.cpp) */
1345     options[1]->buffer_size = 12 * 2352;
1346     // begin playing with only one buffer queued
1347     options[1]->min_buffers = 1;
1348     fs_emu_audio_configure(options);
1349     amiga_set_audio_buffer_size(options[0]->buffer_size);
1350     fs_emu_audio_free_stream_options(options);
1351 #else
1352     // this stream is for paula output and drive clicks
1353     // FIXME: could mix drive clicks in its own stream instead, -might
1354     // give higher quality mixing
1355     fse_audio_stream_options options;
1356     options.struct_size = sizeof(fse_audio_stream_options);
1357     fs_emu_init_audio_stream_options(&options);
1358     options.frequency = fs_emu_audio_output_frequency();
1359     fs_emu_init_audio_stream(0, &options);
1360     amiga_set_audio_buffer_size(options.buffer_size);
1361 
1362     // this stream is for CD audio output (CDTV/CD32)
1363     fs_emu_init_audio_stream_options(&options);
1364     // 12 * 2352 is CDDA_BUFFERS * 2352 (blkdev_cdimage.cpp)
1365     options.buffer_size = 12 * 2352;
1366     // begin playing with only one buffer queued
1367     options.min_buffers = 1;
1368     fs_emu_init_audio_stream(1, &options);
1369 #endif
1370 
1371     amiga_set_audio_callback(audio_callback_function);
1372     amiga_set_cd_audio_callback(audio_callback_function);
1373     amiga_set_event_function(event_handler);
1374 
1375     amiga_set_led_function(led_function);
1376     amiga_on_update_leds(on_update_leds);
1377 
1378     amiga_set_media_function(media_function);
1379     amiga_set_init_function(on_init);
1380 
1381     if (fs_config_get_boolean(OPTION_JIT_COMPILER) == 1) {
1382         amiga_init_jit_compiler();
1383     }
1384 
1385 #ifdef WITH_LUA
1386     amiga_init_lua(fs_emu_acquire_lua, fs_emu_release_lua);
1387     amiga_init_lua_state(fs_emu_get_lua_state());
1388     fs_uae_init_lua_state(fs_emu_get_lua_state());
1389 #endif
1390 
1391     if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_RGBA) {
1392         amiga_set_video_format(AMIGA_VIDEO_FORMAT_RGBA);
1393     } else if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_BGRA) {
1394         amiga_set_video_format(AMIGA_VIDEO_FORMAT_BGRA);
1395     } else if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_R5G6B5) {
1396         amiga_set_video_format(AMIGA_VIDEO_FORMAT_R5G6B5);
1397     } else if (fs_emu_get_video_format() == FS_EMU_VIDEO_FORMAT_R5G5B5A1) {
1398         amiga_set_video_format(AMIGA_VIDEO_FORMAT_R5G5B5A1);
1399     } else {
1400         fs_emu_warning("Unsupported video format requested");
1401     }
1402     amiga_add_rtg_resolution(672, 540);
1403     amiga_add_rtg_resolution(960, 540);
1404     amiga_add_rtg_resolution(672 * 2, 540 * 2);
1405     amiga_add_rtg_resolution(fs_emu_get_windowed_width(),
1406             fs_emu_get_windowed_height());
1407     amiga_add_rtg_resolution(fs_emu_get_fullscreen_width(),
1408             fs_emu_get_fullscreen_height());
1409     fs_uae_init_video();
1410 
1411     //fs_uae_init_keyboard();
1412     fs_uae_init_mouse();
1413     fs_uae_configure_menu();
1414 
1415     const char *value = fs_config_get_const_string("whdload_quit_key");
1416     if (value) {
1417         sscanf(value, "%02x", &whdload_quit_key);
1418         if (whdload_quit_key) {
1419             fs_log("Using WHDLoad quit key: %02X\n", whdload_quit_key);
1420         }
1421     }
1422 
1423     fs_emu_run(main_function);
1424     fs_log("fs-uae shutting down, fs_emu_run returned\n");
1425     if (g_rmdir(fs_uae_state_dir()) == 0) {
1426         fs_log("state dir %s was removed because it was empty\n",
1427                 fs_uae_state_dir());
1428     }
1429     else {
1430         fs_log("state dir %s was not removed (non-empty)\n",
1431                 fs_uae_state_dir());
1432     }
1433     fs_log("end of main function\n");
1434     cleanup_old_files();
1435 
1436 #ifdef WITH_CEF
1437     cef_destroy();
1438 #endif
1439     return 0;
1440 }
1441