--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "uae/string.h"
+
+static TCHAR *dup_tchar(const TCHAR *s)
+{
+ if (!s) {
+ s = _T("");
+ }
+ size_t len = _tcslen(s) + 1;
+ TCHAR *out = xmalloc(TCHAR, len);
+ memcpy(out, s, len * sizeof(TCHAR));
+ return out;
+}
+
+TCHAR *my_strdup_ansi(const char *s)
+{
+ return dup_tchar(s ? s : "");
+}
+
+TCHAR *au(const char *s) { return dup_tchar(s); }
+char *ua(const TCHAR *s) { return dup_tchar(s); }
+TCHAR *aucp(const char *s, unsigned int) { return au(s); }
+char *uacp(const TCHAR *s, unsigned int) { return ua(s); }
+TCHAR *au_fs(const char *s) { return au(s); }
+char *ua_fs(const TCHAR *s, int) { return ua(s); }
+char *uutf8(const TCHAR *s) { return ua(s); }
+TCHAR *utf8u(const char *s) { return au(s); }
+
+char *ua_copy(char *dst, int maxlen, const TCHAR *src)
+{
+ uae_tcslcpy(dst, src ? src : "", maxlen);
+ return dst;
+}
+
+TCHAR *au_copy(TCHAR *dst, int maxlen, const char *src)
+{
+ uae_tcslcpy(dst, src ? src : "", maxlen);
+ return dst;
+}
+
+char *ua_fs_copy(char *dst, int maxlen, const TCHAR *src, int)
+{
+ return ua_copy(dst, maxlen, src);
+}
+
+TCHAR *au_fs_copy(TCHAR *dst, int maxlen, const char *src)
+{
+ return au_copy(dst, maxlen, src);
+}
+
+void unicode_init(void)
+{
+}
+
+void to_lower(TCHAR *s, int len)
+{
+ for (int i = 0; s && s[i] && i < len; i++) {
+ s[i] = (TCHAR)_totlower((unsigned char)s[i]);
+ }
+}
+
+void to_upper(TCHAR *s, int len)
+{
+ for (int i = 0; s && s[i] && i < len; i++) {
+ s[i] = (TCHAR)_totupper((unsigned char)s[i]);
+ }
+}
+
+int uaestrlen(const char *s)
+{
+ return s ? (int)strlen(s) : 0;
+}
+
+int uaetcslen(const TCHAR *s)
+{
+ return s ? (int)_tcslen(s) : 0;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <cstdlib>
+#include <string>
+#include <unistd.h>
+
+#include "options.h"
+#ifdef AVIOUTPUT
+#include "avioutput.h"
+extern int video_recording_active;
+static int unix_avi_audio_codec = AVIAUDIO_AVI;
+#endif
+#include "path_expand.h"
+#include "romscan.h"
+#include "savestate.h"
+#include "sound_unix.h"
+#include "uaeserial_unix.h"
+#ifdef WITH_MIDI
+#include "midi.h"
+#endif
+#include "uae/string.h"
+#include "uae.h"
+#include "zfile.h"
+
+TCHAR start_path_data[MAX_DPATH];
+TCHAR start_path_data_exe[MAX_DPATH];
+TCHAR start_path_plugins[MAX_DPATH];
+int saveimageoriginalpath;
+
+static TCHAR path_configuration[MAX_DPATH];
+static TCHAR path_nvram[MAX_DPATH];
+static TCHAR path_screenshot[MAX_DPATH];
+static TCHAR path_video[MAX_DPATH];
+static TCHAR path_saveimage[MAX_DPATH];
+static TCHAR path_ripper[MAX_DPATH];
+static TCHAR path_data[MAX_DPATH];
+static TCHAR path_rom[MAX_DPATH];
+static TCHAR uaeserial_ports[UNIX_UAESERIAL_MAX_UNITS][256];
+
+static std::string trim_copy(const std::string &s)
+{
+ size_t first = 0;
+ while (first < s.size() && isspace((unsigned char)s[first])) {
+ first++;
+ }
+ size_t last = s.size();
+ while (last > first && isspace((unsigned char)s[last - 1])) {
+ last--;
+ }
+ return s.substr(first, last - first);
+}
+
+static bool parse_path_option(const TCHAR *option, const TCHAR *value, const TCHAR *name, TCHAR *out, int out_size)
+{
+ if (_tcsicmp(option, name)) {
+ return false;
+ }
+ if (!value || !value[0]) {
+ out[0] = 0;
+ return true;
+ }
+ target_expand_environment(value, out, out_size);
+ fixtrailing(out);
+ return true;
+}
+
+static bool parse_rom_path_option(struct uae_prefs *p, const TCHAR *option, const TCHAR *value)
+{
+ if (!parse_path_option(option, value, _T("rom_path"), path_rom, sizeof path_rom / sizeof(TCHAR))) {
+ return false;
+ }
+ if (!p) {
+ return true;
+ }
+ if (!path_rom[0]) {
+ p->path_rom.path[0][0] = 0;
+ return true;
+ }
+ for (int i = 0; i < MAX_PATHS; i++) {
+ if (p->path_rom.path[i][0] == 0 || (i == 0 && (!_tcscmp(p->path_rom.path[i], _T(".\\")) || !_tcscmp(p->path_rom.path[i], _T("./"))))) {
+ uae_tcslcpy(p->path_rom.path[i], path_rom, sizeof p->path_rom.path[i] / sizeof(TCHAR));
+ target_multipath_modified(p);
+ return true;
+ }
+ }
+ uae_tcslcpy(p->path_rom.path[MAX_PATHS - 1], path_rom, sizeof p->path_rom.path[MAX_PATHS - 1] / sizeof(TCHAR));
+ target_multipath_modified(p);
+ return true;
+}
+
+static std::string lowercase_copy(std::string s)
+{
+ for (char &c : s) {
+ c = (char)tolower((unsigned char)c);
+ }
+ return s;
+}
+
+static bool file_exists(const std::string &path)
+{
+ return !path.empty() && access(path.c_str(), F_OK) == 0;
+}
+
+static int parse_bool_value(const std::string &value)
+{
+ std::string v = lowercase_copy(trim_copy(value));
+ return v == "1" || v == "true" || v == "yes" || v == "on";
+}
+
+static bool parse_int_value(const TCHAR *value, int *out)
+{
+ if (!value || !out) {
+ return false;
+ }
+ std::string text = trim_copy(value);
+ if (text.empty()) {
+ return false;
+ }
+ char *end = NULL;
+ long parsed = strtol(text.c_str(), &end, 0);
+ if (!end || *end != 0) {
+ return false;
+ }
+ *out = (int)parsed;
+ return true;
+}
+
+const TCHAR *unix_uaeserial_get_port(int unit)
+{
+ if (unit < 0 || unit >= UNIX_UAESERIAL_MAX_UNITS) {
+ return _T("");
+ }
+ return uaeserial_ports[unit];
+}
+
+void unix_uaeserial_set_port(int unit, const TCHAR *port)
+{
+ if (unit < 0 || unit >= UNIX_UAESERIAL_MAX_UNITS) {
+ return;
+ }
+ uae_tcslcpy(uaeserial_ports[unit], port ? port : _T(""), sizeof uaeserial_ports[unit] / sizeof(TCHAR));
+}
+
+static bool parse_uaeserial_port_option(const TCHAR *option, const TCHAR *value)
+{
+ const TCHAR *prefix = _T("uaeserial_port");
+ int unit = 0;
+
+ if (_tcsicmp(option, prefix)) {
+ size_t prefix_len = _tcslen(prefix);
+ if (_tcsnicmp(option, prefix, prefix_len)) {
+ return false;
+ }
+ const TCHAR *unit_text = option + prefix_len;
+ if (*unit_text == '_') {
+ unit_text++;
+ }
+ if (!*unit_text) {
+ unit = 0;
+ } else if (!parse_int_value(unit_text, &unit)) {
+ return false;
+ }
+ }
+ if (unit < 0 || unit >= UNIX_UAESERIAL_MAX_UNITS) {
+ write_log(_T("UAESER: ignoring unsupported Unix uaeserial unit %d\n"), unit);
+ return true;
+ }
+
+ std::string port = trim_copy(value ? value : "");
+ if (port.size() >= 2 &&
+ ((port[0] == '"' && port[port.size() - 1] == '"') || (port[0] == '\'' && port[port.size() - 1] == '\''))) {
+ port = port.substr(1, port.size() - 2);
+ }
+ if (lowercase_copy(port) == "none") {
+ port.clear();
+ }
+ unix_uaeserial_set_port(unit, port.c_str());
+ return true;
+}
+
+static int activity_priority_index_from_value(int value, int defpri)
+{
+ switch (value) {
+ case 1:
+ return 0;
+ case 0:
+ return 1;
+ case -1:
+ return 2;
+ case -2:
+ return 3;
+ default:
+ return defpri;
+ }
+}
+
+static const TCHAR *configmult[] = { _T("1x"), _T("2x"), _T("3x"), _T("4x"), _T("5x"), _T("6x"), _T("7x"), _T("8x"), NULL };
+static const TCHAR *uaescsimode[] = { _T("SCSIEMU"), _T("SPTI"), _T("SPTI+SCSISCAN"), NULL };
+
+int target_cfgfile_load(struct uae_prefs *p, const TCHAR *filename, int type, int isdefault)
+{
+ if (isdefault && type == CONFIG_TYPE_DEFAULT && !file_exists(filename)) {
+ return 1;
+ }
+ int loaded_type = type;
+ return cfgfile_load(p, filename, &loaded_type, 0, !isdefault);
+}
+
+int target_parse_option(struct uae_prefs *p, const TCHAR *option, const TCHAR *value, int)
+{
+ if (!_tcsicmp(option, _T("ui.recursive_roms"))) {
+ unix_romscan_set_recursive(parse_bool_value(value ? value : ""));
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("middle_mouse"))) {
+ if (parse_bool_value(value ? value : "")) {
+ p->input_mouse_untrap |= MOUSEUNTRAP_MIDDLEBUTTON;
+ } else {
+ p->input_mouse_untrap &= ~MOUSEUNTRAP_MIDDLEBUTTON;
+ }
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("active_not_captured_pause"))) {
+ p->win32_active_nocapture_pause = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("active_not_captured_nosound"))) {
+ p->win32_active_nocapture_nosound = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("inactive_pause"))) {
+ p->win32_inactive_pause = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("inactive_nosound"))) {
+ p->win32_inactive_nosound = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("iconified_pause"))) {
+ p->win32_iconified_pause = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("iconified_nosound"))) {
+ p->win32_iconified_nosound = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("active_input"))
+ || !_tcsicmp(option, _T("inactive_input"))
+ || !_tcsicmp(option, _T("iconified_input"))) {
+ int parsed = 0;
+ if (!parse_int_value(value, &parsed)) {
+ return 0;
+ }
+ if (!_tcsicmp(option, _T("active_input"))) {
+ p->win32_active_input = parsed;
+ } else if (!_tcsicmp(option, _T("inactive_input"))) {
+ p->win32_inactive_input = parsed;
+ } else {
+ p->win32_iconified_input = parsed;
+ }
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("active_priority"))
+ || !_tcsicmp(option, _T("activepriority"))
+ || !_tcsicmp(option, _T("inactive_priority"))
+ || !_tcsicmp(option, _T("iconified_priority"))) {
+ int parsed = 0;
+ if (!parse_int_value(value, &parsed)) {
+ return 0;
+ }
+ if (!_tcsicmp(option, _T("active_priority")) || !_tcsicmp(option, _T("activepriority"))) {
+ p->win32_active_capture_priority = activity_priority_index_from_value(parsed, 1);
+ } else if (!_tcsicmp(option, _T("inactive_priority"))) {
+ p->win32_inactive_priority = activity_priority_index_from_value(parsed, 1);
+ } else {
+ p->win32_iconified_priority = activity_priority_index_from_value(parsed, 2);
+ }
+ return 1;
+ }
+ if (cfgfile_intval(option, value, _T("recording_width"), &p->aviout_width, 1)
+ || cfgfile_intval(option, value, _T("recording_height"), &p->aviout_height, 1)
+ || cfgfile_intval(option, value, _T("recording_x"), &p->aviout_xoffset, 1)
+ || cfgfile_intval(option, value, _T("recording_y"), &p->aviout_yoffset, 1)
+ || cfgfile_intval(option, value, _T("screenshot_width"), &p->screenshot_width, 1)
+ || cfgfile_intval(option, value, _T("screenshot_height"), &p->screenshot_height, 1)
+ || cfgfile_intval(option, value, _T("screenshot_x"), &p->screenshot_xoffset, 1)
+ || cfgfile_intval(option, value, _T("screenshot_y"), &p->screenshot_yoffset, 1)
+ || cfgfile_intval(option, value, _T("screenshot_min_width"), &p->screenshot_min_width, 1)
+ || cfgfile_intval(option, value, _T("screenshot_min_height"), &p->screenshot_min_height, 1)
+ || cfgfile_intval(option, value, _T("screenshot_max_width"), &p->screenshot_max_width, 1)
+ || cfgfile_intval(option, value, _T("screenshot_max_height"), &p->screenshot_max_height, 1)
+ || cfgfile_intval(option, value, _T("screenshot_output_width_limit"), &p->screenshot_output_width, 1)
+ || cfgfile_intval(option, value, _T("screenshot_output_height_limit"), &p->screenshot_output_height, 1)) {
+ return 1;
+ }
+ if (cfgfile_strval(option, value, _T("uaescsimode"), &p->win32_uaescsimode, uaescsimode, 0)) {
+ return 1;
+ }
+ {
+ TCHAR tmpbuf[CONFIG_BLEN];
+ if (cfgfile_string(option, value, _T("rtg_vblank"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR))) {
+ if (!_tcsicmp(tmpbuf, _T("real"))) {
+ p->win32_rtgvblankrate = -1;
+ } else if (!_tcsicmp(tmpbuf, _T("disabled"))) {
+ p->win32_rtgvblankrate = -2;
+ } else if (!_tcsicmp(tmpbuf, _T("chipset"))) {
+ p->win32_rtgvblankrate = 0;
+ } else {
+ p->win32_rtgvblankrate = _tstol(tmpbuf);
+ }
+ return 1;
+ }
+ }
+ if (cfgfile_strval(option, value, _T("screenshot_mult_width"), &p->screenshot_xmult, configmult, 0)
+ || cfgfile_strval(option, value, _T("screenshot_mult_height"), &p->screenshot_ymult, configmult, 0)) {
+ return 1;
+ }
+#ifdef AVIOUTPUT
+ if (!_tcsicmp(option, _T("screenshot_original_size")) || !_tcsicmp(option, _T("ui.screenshot_original_size"))) {
+ screenshot_originalsize = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("screenshot_paletted")) || !_tcsicmp(option, _T("ui.screenshot_paletted"))) {
+ screenshot_paletteindexed = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("screenshot_clip")) || !_tcsicmp(option, _T("ui.screenshot_clip"))) {
+ screenshot_clipmode = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("screenshot_auto")) || !_tcsicmp(option, _T("ui.screenshot_auto"))) {
+ screenshot_multi = parse_bool_value(value ? value : "") ? -1 : 0;
+ if (screenshot_multi) {
+ video_recording_active |= 2;
+ } else {
+ video_recording_active &= ~2;
+ }
+ return 1;
+ }
+ {
+ TCHAR tmpbuf[MAX_DPATH];
+ if (cfgfile_string_escape(option, value, _T("output_file"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR)) ||
+ cfgfile_string_escape(option, value, _T("ui.output_file"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR))) {
+ _tcsncpy(avioutput_filename_gui, tmpbuf, sizeof avioutput_filename_gui / sizeof(TCHAR) - 1);
+ avioutput_filename_gui[sizeof avioutput_filename_gui / sizeof(TCHAR) - 1] = 0;
+ return 1;
+ }
+ }
+ if (!_tcsicmp(option, _T("output_frame_limiter_disabled")) || !_tcsicmp(option, _T("ui.output_frame_limiter_disabled"))) {
+ avioutput_framelimiter = parse_bool_value(value ? value : "") ? 0 : 1;
+ if (!avioutput_framelimiter) {
+ avioutput_nosoundoutput = 1;
+ }
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_original_size")) || !_tcsicmp(option, _T("ui.output_original_size"))) {
+ avioutput_originalsize = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_no_sound")) || !_tcsicmp(option, _T("ui.output_no_sound"))) {
+ avioutput_nosoundoutput = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_no_sound_sync")) || !_tcsicmp(option, _T("ui.output_no_sound_sync"))) {
+ avioutput_nosoundsync = parse_bool_value(value ? value : "");
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_audio_codec")) || !_tcsicmp(option, _T("ui.output_audio_codec"))) {
+ if (value && (!_tcsicmp(value, _T("wav")) || !_tcsicmp(value, _T("wave")))) {
+ unix_avi_audio_codec = AVIAUDIO_WAV;
+ } else {
+ unix_avi_audio_codec = AVIAUDIO_AVI;
+ }
+ if (avioutput_audio) {
+ avioutput_audio = unix_avi_audio_codec;
+ }
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_video_codec")) || !_tcsicmp(option, _T("ui.output_video_codec"))) {
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_audio")) || !_tcsicmp(option, _T("ui.output_audio"))) {
+ avioutput_audio = parse_bool_value(value ? value : "") ? unix_avi_audio_codec : 0;
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_video")) || !_tcsicmp(option, _T("ui.output_video"))) {
+ avioutput_video = parse_bool_value(value ? value : "") ? 1 : 0;
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("output_enabled")) || !_tcsicmp(option, _T("ui.output_enabled"))) {
+ if (parse_bool_value(value ? value : "")) {
+ AVIOutput_Begin(false);
+ } else {
+ AVIOutput_End();
+ }
+ return 1;
+ }
+#endif
+ if (!_tcsicmp(option, _T("serial_port"))) {
+ std::string port = trim_copy(value ? value : "");
+ if (port.size() >= 2 &&
+ ((port[0] == '"' && port[port.size() - 1] == '"') || (port[0] == '\'' && port[port.size() - 1] == '\''))) {
+ port = port.substr(1, port.size() - 2);
+ }
+ if (lowercase_copy(port) == "none") {
+ port.clear();
+ }
+ uae_tcslcpy(p->sername, port.c_str(), sizeof p->sername / sizeof(TCHAR));
+ p->use_serial = p->sername[0] != 0;
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("parallel_port"))) {
+ std::string port = trim_copy(value ? value : "");
+ if (port.size() >= 2 &&
+ ((port[0] == '"' && port[port.size() - 1] == '"') || (port[0] == '\'' && port[port.size() - 1] == '\''))) {
+ port = port.substr(1, port.size() - 2);
+ }
+ if (lowercase_copy(port) == "none") {
+ port.clear();
+ } else if (lowercase_copy(port) == "default") {
+ port = DEFPRTNAME;
+ }
+ uae_tcslcpy(p->prtname, port.c_str(), sizeof p->prtname / sizeof(TCHAR));
+ return 1;
+ }
+ if (parse_uaeserial_port_option(option, value)) {
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("soundcard"))) {
+ int parsed = 0;
+ if (!parse_int_value(value, &parsed)) {
+ return 0;
+ }
+ if (parsed < 0 || parsed >= unix_sound_device_count()) {
+ parsed = 0;
+ }
+ p->win32_soundcard = parsed;
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("soundcardname"))) {
+ int index = unix_sound_device_index_from_config_name(value);
+ if (index >= 0) {
+ p->win32_soundcard = index;
+ }
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("samplersoundcard")) || !_tcsicmp(option, _T("sampler_soundcard"))) {
+ int parsed = 0;
+ if (!parse_int_value(value, &parsed)) {
+ return 0;
+ }
+ if (parsed < 0 || parsed >= unix_sampler_device_count()) {
+ parsed = -1;
+ }
+ p->win32_samplersoundcard = parsed;
+ return 1;
+ }
+ if (!_tcsicmp(option, _T("samplersoundcardname")) || !_tcsicmp(option, _T("sampler_soundcardname"))) {
+ int index = unix_sampler_device_index_from_config_name(value);
+ if (index >= 0) {
+ p->win32_samplersoundcard = index;
+ }
+ return 1;
+ }
+ if (cfgfile_intval(option, value, _T("midi_device"), &p->win32_midioutdev, 1)
+ || cfgfile_intval(option, value, _T("midiout_device"), &p->win32_midioutdev, 1)) {
+ return 1;
+ }
+ if (cfgfile_intval(option, value, _T("midiin_device"), &p->win32_midiindev, 1)) {
+#ifndef WITH_MIDI
+ p->win32_midiindev = -1;
+#endif
+ return 1;
+ }
+ if (cfgfile_yesno(option, value, _T("midirouter"), &p->win32_midirouter)) {
+#ifndef WITH_MIDI
+ p->win32_midirouter = false;
+#endif
+ return 1;
+ }
+ TCHAR tmpbuf[256];
+ if (cfgfile_string_escape(option, value, _T("midiout_device_name"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR))) {
+#ifdef WITH_MIDI
+ p->win32_midioutdev = unix_midi_output_device_id_from_config_name(tmpbuf);
+#else
+ p->win32_midioutdev = !_tcsicmp(tmpbuf, _T("default")) ? -1 : -2;
+#endif
+ return 1;
+ }
+ if (cfgfile_string_escape(option, value, _T("midiin_device_name"), tmpbuf, sizeof tmpbuf / sizeof(TCHAR))) {
+#ifdef WITH_MIDI
+ p->win32_midiindev = unix_midi_input_device_id_from_config_name(tmpbuf);
+#else
+ p->win32_midiindev = -1;
+#endif
+ return 1;
+ }
+ if (parse_path_option(option, value, _T("config_path"), path_configuration, sizeof path_configuration / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.config_path"), path_configuration, sizeof path_configuration / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("nvram_path"), path_nvram, sizeof path_nvram / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.nvram_path"), path_nvram, sizeof path_nvram / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("screenshot_path"), path_screenshot, sizeof path_screenshot / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.screenshot_path"), path_screenshot, sizeof path_screenshot / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("video_path"), path_video, sizeof path_video / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.video_path"), path_video, sizeof path_video / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("saveimage_path"), path_saveimage, sizeof path_saveimage / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.saveimage_path"), path_saveimage, sizeof path_saveimage / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("rip_path"), path_ripper, sizeof path_ripper / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ripper_path"), path_ripper, sizeof path_ripper / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.rip_path"), path_ripper, sizeof path_ripper / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("data_path"), path_data, sizeof path_data / sizeof(TCHAR))
+ || parse_path_option(option, value, _T("ui.data_path"), path_data, sizeof path_data / sizeof(TCHAR))
+ || parse_rom_path_option(p, option, value)) {
+ return 1;
+ }
+ return 0;
+}
+
+void target_save_options(struct zfile *f, struct uae_prefs *p)
+{
+ cfgfile_target_dwrite_str(f, _T("serial_port"), p->sername[0] ? p->sername : _T("none"));
+ cfgfile_target_dwrite_str_escape(f, _T("parallel_port"), p->prtname[0] ? p->prtname : _T("none"));
+ for (int i = 0; i < UNIX_UAESERIAL_MAX_UNITS; i++) {
+ if (uaeserial_ports[i][0]) {
+ TCHAR option[64];
+ _stprintf(option, _T("uaeserial_port%d"), i);
+ cfgfile_target_write_str(f, option, uaeserial_ports[i]);
+ }
+ }
+
+ int index = p->win32_soundcard;
+ if (index < 0 || index >= unix_sound_device_count()) {
+ index = 0;
+ }
+ cfgfile_target_write(f, _T("soundcard"), _T("%d"), index);
+ const TCHAR *name = unix_sound_device_config_name(index);
+ if (name && name[0]) {
+ cfgfile_target_write_str(f, _T("soundcardname"), name);
+ }
+ if (p->win32_samplersoundcard >= 0 && p->win32_samplersoundcard < unix_sampler_device_count()) {
+ cfgfile_target_write(f, _T("samplersoundcard"), _T("%d"), p->win32_samplersoundcard);
+ const TCHAR *sampler_name = unix_sampler_device_config_name(p->win32_samplersoundcard);
+ if (sampler_name && sampler_name[0]) {
+ cfgfile_target_write_str(f, _T("samplersoundcardname"), sampler_name);
+ }
+ }
+ cfgfile_target_dwrite(f, _T("midiout_device"), _T("%d"), p->win32_midioutdev);
+ cfgfile_target_dwrite(f, _T("midiin_device"), _T("%d"), p->win32_midiindev);
+#ifdef WITH_MIDI
+ cfgfile_target_dwrite_str_escape(f, _T("midiout_device_name"), unix_midi_output_device_config_name_for_id(p->win32_midioutdev));
+ cfgfile_target_dwrite_str_escape(f, _T("midiin_device_name"), unix_midi_input_device_config_name_for_id(p->win32_midiindev));
+#else
+ cfgfile_target_dwrite_str_escape(f, _T("midiout_device_name"), p->win32_midioutdev == -1 ? _T("default") : _T("none"));
+ cfgfile_target_dwrite_str_escape(f, _T("midiin_device_name"), _T("none"));
+#endif
+ cfgfile_target_dwrite_bool(f, _T("midirouter"), p->win32_midirouter);
+ int scsimode = p->win32_uaescsimode;
+ if (scsimode < 0 || scsimode > UAESCSI_LAST) {
+ scsimode = UAESCSI_SPTI;
+ }
+ cfgfile_target_dwrite_str(f, _T("uaescsimode"), uaescsimode[scsimode]);
+ if (p->win32_rtgvblankrate <= 0) {
+ cfgfile_target_dwrite_str(f, _T("rtg_vblank"),
+ p->win32_rtgvblankrate == -1 ? _T("real") : (p->win32_rtgvblankrate == -2 ? _T("disabled") : _T("chipset")));
+ } else {
+ cfgfile_target_dwrite(f, _T("rtg_vblank"), _T("%d"), p->win32_rtgvblankrate);
+ }
+ cfgfile_target_dwrite(f, _T("recording_width"), _T("%d"), p->aviout_width);
+ cfgfile_target_dwrite(f, _T("recording_height"), _T("%d"), p->aviout_height);
+ cfgfile_target_dwrite(f, _T("recording_x"), _T("%d"), p->aviout_xoffset);
+ cfgfile_target_dwrite(f, _T("recording_y"), _T("%d"), p->aviout_yoffset);
+ cfgfile_target_dwrite(f, _T("screenshot_width"), _T("%d"), p->screenshot_width);
+ cfgfile_target_dwrite(f, _T("screenshot_height"), _T("%d"), p->screenshot_height);
+ cfgfile_target_dwrite(f, _T("screenshot_x"), _T("%d"), p->screenshot_xoffset);
+ cfgfile_target_dwrite(f, _T("screenshot_y"), _T("%d"), p->screenshot_yoffset);
+ cfgfile_target_dwrite(f, _T("screenshot_min_width"), _T("%d"), p->screenshot_min_width);
+ cfgfile_target_dwrite(f, _T("screenshot_min_height"), _T("%d"), p->screenshot_min_height);
+ cfgfile_target_dwrite(f, _T("screenshot_max_width"), _T("%d"), p->screenshot_max_width);
+ cfgfile_target_dwrite(f, _T("screenshot_max_height"), _T("%d"), p->screenshot_max_height);
+ cfgfile_target_dwrite(f, _T("screenshot_output_width_limit"), _T("%d"), p->screenshot_output_width);
+ cfgfile_target_dwrite(f, _T("screenshot_output_height_limit"), _T("%d"), p->screenshot_output_height);
+ cfgfile_target_dwrite_str(f, _T("screenshot_mult_width"), configmult[p->screenshot_xmult]);
+ cfgfile_target_dwrite_str(f, _T("screenshot_mult_height"), configmult[p->screenshot_ymult]);
+#ifdef AVIOUTPUT
+ cfgfile_target_dwrite_bool(f, _T("screenshot_original_size"), screenshot_originalsize != 0);
+ cfgfile_target_dwrite_bool(f, _T("screenshot_paletted"), screenshot_paletteindexed != 0);
+ cfgfile_target_dwrite_bool(f, _T("screenshot_clip"), screenshot_clipmode != 0);
+ cfgfile_target_dwrite_bool(f, _T("screenshot_auto"), screenshot_multi != 0);
+ if (avioutput_filename_gui[0]) {
+ cfgfile_target_dwrite_str_escape(f, _T("output_file"), avioutput_filename_gui);
+ }
+ cfgfile_target_dwrite_bool(f, _T("output_frame_limiter_disabled"), avioutput_framelimiter == 0);
+ cfgfile_target_dwrite_bool(f, _T("output_original_size"), avioutput_originalsize != 0);
+ cfgfile_target_dwrite_bool(f, _T("output_no_sound"), avioutput_nosoundoutput != 0);
+ cfgfile_target_dwrite_bool(f, _T("output_no_sound_sync"), avioutput_nosoundsync != 0);
+ cfgfile_target_write_str(f, _T("output_audio_codec"),
+ avioutput_audio == AVIAUDIO_WAV ? _T("wav") : _T("pcm"));
+ cfgfile_target_write_str(f, _T("output_video_codec"), _T("dib"));
+ cfgfile_target_dwrite_bool(f, _T("output_audio"), avioutput_audio != 0);
+ cfgfile_target_dwrite_bool(f, _T("output_video"), avioutput_video != 0);
+ cfgfile_target_dwrite_bool(f, _T("output_enabled"), avioutput_requested != 0);
+#endif
+ if (path_configuration[0]) {
+ cfgfile_target_write_str(f, _T("config_path"), path_configuration);
+ }
+ if (path_nvram[0]) {
+ cfgfile_target_write_str(f, _T("nvram_path"), path_nvram);
+ }
+ if (path_screenshot[0]) {
+ cfgfile_target_write_str(f, _T("screenshot_path"), path_screenshot);
+ }
+ if (path_video[0]) {
+ cfgfile_target_write_str(f, _T("video_path"), path_video);
+ }
+ if (path_saveimage[0]) {
+ cfgfile_target_write_str(f, _T("saveimage_path"), path_saveimage);
+ }
+ if (path_ripper[0]) {
+ cfgfile_target_write_str(f, _T("rip_path"), path_ripper);
+ }
+ if (path_data[0]) {
+ cfgfile_target_write_str(f, _T("data_path"), path_data);
+ }
+ if (path_rom[0]) {
+ cfgfile_target_write_str(f, _T("rom_path"), path_rom);
+ }
+}
+
+void target_default_options(struct uae_prefs *p, int)
+{
+ path_configuration[0] = 0;
+ path_nvram[0] = 0;
+ path_screenshot[0] = 0;
+ path_video[0] = 0;
+ path_saveimage[0] = 0;
+ path_ripper[0] = 0;
+ path_data[0] = 0;
+ path_rom[0] = 0;
+ for (int i = 0; i < UNIX_UAESERIAL_MAX_UNITS; i++) {
+ uaeserial_ports[i][0] = 0;
+ }
+ unix_romscan_mark_dirty();
+ p->rtg_dacswitch = true;
+ p->rtg_hardwaresprite = true;
+ p->win32_rtgvblankrate = 0;
+ p->win32_samplersoundcard = -1;
+ p->win32_midioutdev = -2;
+ p->win32_midiindev = -1;
+ p->win32_midirouter = false;
+}
+
+void target_fixup_options(struct uae_prefs *p)
+{
+#ifndef WITH_MIDI
+ p->win32_midiindev = -1;
+ p->win32_midirouter = false;
+#endif
+ if (p->win32_uaescsimode > UAESCSI_LAST) {
+ p->win32_uaescsimode = UAESCSI_SPTI;
+ }
+ unix_romscan_refresh(p, false);
+}
+
+void target_multipath_modified(struct uae_prefs*)
+{
+ unix_romscan_mark_dirty();
+}
+
+bool target_isrelativemode(void)
+{
+ return false;
+}
+
+TCHAR *target_expand_environment(const TCHAR *path, TCHAR *out, int maxlen)
+{
+ if (!path) {
+ return NULL;
+ }
+
+ std::string expanded = unix_expand_path(path);
+ if (out) {
+ uae_tcslcpy(out, expanded.c_str(), maxlen);
+ return out;
+ }
+ return my_strdup(expanded.c_str());
+}
+
+bool get_plugin_path(TCHAR *out, int size, const TCHAR *path)
+{
+ uae_tcslcpy(out, path, size);
+ return true;
+}
+
+void stripslashes(TCHAR *p)
+{
+ while (*p) {
+ if (*p == '\\') {
+ *p = '/';
+ }
+ p++;
+ }
+}
+
+void fixtrailing(TCHAR *p)
+{
+ int len = _tcslen(p);
+ if (len > 0 && p[len - 1] != '/') {
+ _tcscat(p, "/");
+ }
+}
+
+void fullpath(TCHAR *path, int size)
+{
+ fullpath(path, size, false);
+}
+
+void fullpath(TCHAR *path, int size, bool)
+{
+ if (!path || !path[0]) {
+ return;
+ }
+ const std::string absolute = unix_absolute_path(path);
+ uae_tcslcpy(path, absolute.c_str(), size);
+}
+
+void getpathpart(TCHAR *outpath, int size, const TCHAR *inpath)
+{
+ uae_tcslcpy(outpath, inpath, size);
+ TCHAR *slash = _tcsrchr(outpath, '/');
+ if (slash) {
+ slash[1] = 0;
+ } else {
+ outpath[0] = 0;
+ }
+}
+
+void getfilepart(TCHAR *out, int size, const TCHAR *path)
+{
+ const TCHAR *slash = _tcsrchr(path, '/');
+ uae_tcslcpy(out, slash ? slash + 1 : path, size);
+}
+
+bool samepath(const TCHAR *p1, const TCHAR *p2)
+{
+ return _tcscmp(p1, p2) == 0;
+}
+
+static void fetch_home_path(TCHAR *out, int size)
+{
+ const char *home = getenv("HOME");
+ uae_tcslcpy(out, home ? home : ".", size);
+ fixtrailing(out);
+}
+
+static void fetch_user_data_path(TCHAR *out, int size, const char *subdir)
+{
+ if (!out || size <= 0) {
+ return;
+ }
+ const char *home = getenv("HOME");
+ const char *base = home ? home : ".";
+ if (subdir && subdir[0]) {
+ snprintf(out, (size_t)size, "%s/Documents/WinUAE/%s", base, subdir);
+ } else {
+ snprintf(out, (size_t)size, "%s/Documents/WinUAE", base);
+ }
+ fixtrailing(out);
+}
+
+static void fetch_user_data_path_override(TCHAR *out, int size, const TCHAR *override_path, const char *subdir)
+{
+ if (override_path && override_path[0]) {
+ uae_tcslcpy(out, override_path, size);
+ fixtrailing(out);
+ } else {
+ fetch_user_data_path(out, size, subdir);
+ }
+}
+
+void fetch_saveimagepath(TCHAR *out, int size, int) { fetch_user_data_path_override(out, size, path_saveimage, "SaveImages"); }
+void fetch_configurationpath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_configuration, "Configuration"); }
+void fetch_nvrampath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_nvram, "NVRAMs"); }
+void fetch_luapath(TCHAR *out, int size) { fetch_home_path(out, size); }
+void fetch_screenshotpath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_screenshot, "Screenshots"); }
+void fetch_ripperpath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_ripper, "Rips"); }
+void fetch_statefilepath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_statefile, "Save States"); }
+void fetch_inputfilepath(TCHAR *out, int size) { fetch_home_path(out, size); }
+void fetch_datapath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_data, NULL); }
+void fetch_rompath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_rom, "Kickstarts"); }
+void fetch_videopath(TCHAR *out, int size) { fetch_user_data_path_override(out, size, path_video, "Videos"); }
+
+void target_getdate(int *y, int *m, int *d)
+{
+ *y = 2026;
+ *m = 5;
+ *d = 10;
+}
--- /dev/null
+#ifndef WINUAE_OD_UNIX_CONFIG_H
+#define WINUAE_OD_UNIX_CONFIG_H
+
+#include "sysconfig.h"
+
+#endif /* WINUAE_OD_UNIX_CONFIG_H */
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#include "fsdb.h"
+#include "fsusage.h"
+#include "uae/io.h"
+#include "uae/string.h"
+#include "zfile.h"
+
+struct my_opendir_s {
+ DIR *dir;
+};
+
+struct my_openfile_s {
+ int fd;
+};
+
+bool my_issamepath(const TCHAR *path1, const TCHAR *path2);
+
+static uae_u32 mode_from_stat(const struct stat &st)
+{
+ uae_u32 mode = 0;
+ if (S_ISDIR(st.st_mode)) {
+ mode |= FILEFLAG_DIR;
+ }
+ if (st.st_mode & S_IRUSR) {
+ mode |= FILEFLAG_READ;
+ }
+ if (st.st_mode & S_IWUSR) {
+ mode |= FILEFLAG_WRITE;
+ }
+ if (st.st_mode & S_IXUSR) {
+ mode |= FILEFLAG_EXECUTE;
+ }
+ return mode;
+}
+
+FILE *uae_tfopen(const TCHAR *path, const TCHAR *mode)
+{
+ return uae_unix_tfopen(path, mode);
+}
+
+int dos_errno(void)
+{
+ switch (errno) {
+ case 0: return 0;
+ case ENOENT: return ERROR_OBJECT_NOT_AROUND;
+ case EACCES:
+ case EPERM: return ERROR_WRITE_PROTECTED;
+ case ENOTDIR: return ERROR_DIR_NOT_FOUND;
+ case EEXIST: return ERROR_OBJECT_EXISTS;
+ case ENOSPC: return ERROR_DISK_IS_FULL;
+ case ENOTEMPTY: return ERROR_DIRECTORY_NOT_EMPTY;
+ default: return ERROR_OBJECT_NOT_AROUND;
+ }
+}
+
+my_opendir_s *my_opendir(const TCHAR *name, const TCHAR *)
+{
+ DIR *dir = opendir(name);
+ if (!dir) {
+ return NULL;
+ }
+ my_opendir_s *out = xcalloc(my_opendir_s, 1);
+ out->dir = dir;
+ return out;
+}
+
+my_opendir_s *my_opendir(const TCHAR *name)
+{
+ return my_opendir(name, _T("*"));
+}
+
+void my_closedir(my_opendir_s *mod)
+{
+ if (!mod) {
+ return;
+ }
+ if (mod->dir) {
+ closedir(mod->dir);
+ }
+ xfree(mod);
+}
+
+int my_readdir(my_opendir_s *mod, TCHAR *name)
+{
+ if (!mod || !mod->dir || !name) {
+ return 0;
+ }
+ for (;;) {
+ struct dirent *de = readdir(mod->dir);
+ if (!de) {
+ return 0;
+ }
+ if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+ continue;
+ }
+ uae_tcslcpy(name, de->d_name, MAX_DPATH);
+ return 1;
+ }
+}
+
+int my_rmdir(const TCHAR *name) { return rmdir(name); }
+int my_mkdir(const TCHAR *name) { return mkdir(name, 0777); }
+int my_unlink(const TCHAR *name, bool) { return unlink(name); }
+int my_rename(const TCHAR *oldname, const TCHAR *newname) { return rename(oldname, newname); }
+int my_truncate(const TCHAR *name, uae_u64 len) { return truncate(name, (off_t)len); }
+
+my_openfile_s *my_open(const TCHAR *name, int flags)
+{
+ int fd = open(name, flags, 0666);
+ if (fd < 0) {
+ return NULL;
+ }
+ my_openfile_s *out = xcalloc(my_openfile_s, 1);
+ out->fd = fd;
+ return out;
+}
+
+void my_close(my_openfile_s *mos)
+{
+ if (!mos) {
+ return;
+ }
+ if (mos->fd >= 0) {
+ close(mos->fd);
+ }
+ xfree(mos);
+}
+
+uae_s64 my_lseek(my_openfile_s *mos, uae_s64 offset, int whence)
+{
+ return mos ? (uae_s64)lseek(mos->fd, (off_t)offset, whence) : -1;
+}
+
+uae_s64 my_fsize(my_openfile_s *mos)
+{
+ struct stat st;
+ if (!mos || fstat(mos->fd, &st) != 0) {
+ return -1;
+ }
+ return (uae_s64)st.st_size;
+}
+
+unsigned int my_read(my_openfile_s *mos, void *b, unsigned int size)
+{
+ ssize_t ret = mos ? read(mos->fd, b, size) : -1;
+ return ret < 0 ? 0 : (unsigned int)ret;
+}
+
+unsigned int my_write(my_openfile_s *mos, void *b, unsigned int size)
+{
+ ssize_t ret = mos ? write(mos->fd, b, size) : -1;
+ return ret < 0 ? 0 : (unsigned int)ret;
+}
+
+int my_existsfile(const TCHAR *name)
+{
+ struct stat st;
+ return name && stat(name, &st) == 0 && S_ISREG(st.st_mode);
+}
+
+int my_existsdir(const TCHAR *name)
+{
+ struct stat st;
+ return name && stat(name, &st) == 0 && S_ISDIR(st.st_mode);
+}
+
+bool my_existsfiledir(const TCHAR *name)
+{
+ struct stat st;
+ return name && stat(name, &st) == 0;
+}
+
+FILE *my_opentext(const TCHAR *name)
+{
+ return uae_tfopen(name, _T("r"));
+}
+
+bool my_stat(const TCHAR *name, struct mystat *ms)
+{
+ struct stat st;
+ if (!name || !ms || stat(name, &st) != 0) {
+ return false;
+ }
+ ms->size = (uae_s64)st.st_size;
+ ms->mode = mode_from_stat(st);
+ ms->mtime.tv_sec = (uae_s64)st.st_mtime;
+ ms->mtime.tv_usec = 0;
+ return true;
+}
+
+bool my_utime(const TCHAR *name, struct mytimeval *tv)
+{
+ if (!name) {
+ return false;
+ }
+ if (!tv) {
+ return utimes(name, NULL) == 0;
+ }
+ struct timeval times[2];
+ times[0].tv_sec = (time_t)tv->tv_sec;
+ times[0].tv_usec = tv->tv_usec;
+ times[1] = times[0];
+ return utimes(name, times) == 0;
+}
+
+bool my_chmod(const TCHAR *name, uae_u32 mode)
+{
+ struct stat st;
+ if (!name || stat(name, &st) != 0) {
+ return false;
+ }
+ mode_t m = st.st_mode;
+ if (mode & FILEFLAG_WRITE) {
+ m |= S_IWUSR;
+ } else {
+ m &= ~S_IWUSR;
+ }
+ return chmod(name, m) == 0;
+}
+
+bool my_resolveshortcut(TCHAR *, int) { return false; }
+bool my_resolvessymboliclink(TCHAR *, int) { return false; }
+bool my_resolvesoftlink(TCHAR *, int, bool) { return false; }
+bool my_isfilehidden(const TCHAR *path) { return path && path[0] == '.'; }
+void my_setfilehidden(const TCHAR *, bool) {}
+int my_readonlyfile(const TCHAR *path)
+{
+ return access(path, W_OK) != 0;
+}
+
+const TCHAR *my_getfilepart(const TCHAR *filename)
+{
+ const TCHAR *slash = filename ? _tcsrchr(filename, FSDB_DIR_SEPARATOR) : NULL;
+ return slash ? slash + 1 : filename;
+}
+
+void my_canonicalize_path(const TCHAR *path, TCHAR *out, int size)
+{
+ if (!path || !out || size <= 0) {
+ return;
+ }
+ char resolved[PATH_MAX];
+ if (realpath(path, resolved)) {
+ uae_tcslcpy(out, resolved, size);
+ } else {
+ uae_tcslcpy(out, path, size);
+ }
+}
+
+int my_setcurrentdir(const TCHAR *curdir, TCHAR *oldcur)
+{
+ if (oldcur) {
+ if (!getcwd(oldcur, MAX_DPATH)) {
+ oldcur[0] = 0;
+ }
+ }
+ return curdir ? chdir(curdir) : -1;
+}
+
+int my_issamevolume(const TCHAR *path1, const TCHAR *path2, TCHAR *path)
+{
+ if (path && path1) {
+ uae_tcslcpy(path, path1, MAX_DPATH);
+ }
+ return my_issamepath(path1, path2);
+}
+
+bool my_issamepath(const TCHAR *path1, const TCHAR *path2)
+{
+ char r1[PATH_MAX], r2[PATH_MAX];
+ const char *p1 = realpath(path1, r1) ? r1 : path1;
+ const char *p2 = realpath(path2, r2) ? r2 : path2;
+ return p1 && p2 && !_tcscmp(p1, p2);
+}
+
+bool my_createsoftlink(const TCHAR *path, const TCHAR *target)
+{
+ return symlink(target, path) == 0;
+}
+
+bool my_createshortcut(const TCHAR *, const TCHAR *, const TCHAR *) { return false; }
+void makesafefilename(TCHAR *s, bool)
+{
+ for (; s && *s; s++) {
+ if (*s == '/' || *s == ':') {
+ *s = '_';
+ }
+ }
+}
+
+int my_getvolumeinfo(const TCHAR *)
+{
+ return 0;
+}
+
+int get_fs_usage(const TCHAR *path, const TCHAR *, struct fs_usage *fsp)
+{
+ struct statvfs svfs;
+ if (!path || !fsp || statvfs(path, &svfs) != 0) {
+ return -1;
+ }
+ uae_u64 bsize = svfs.f_frsize ? svfs.f_frsize : svfs.f_bsize;
+ fsp->total = (uae_u64)svfs.f_blocks * bsize / 512;
+ fsp->avail = (uae_u64)svfs.f_bavail * bsize / 512;
+ return 0;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "options.h"
+#include "traps.h"
+#include "custom.h"
+#include "inputdevice.h"
+#include "gui.h"
+#include "target_main.h"
+#include "savestate.h"
+#include "sounddep/sound.h"
+
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+#include "qt/launcher_bridge.h"
+#endif
+
+unsigned int gui_ledstate;
+
+static int unix_gui_argc;
+static TCHAR **unix_gui_argv;
+
+void target_main_set_args(int argc, TCHAR **argv)
+{
+ unix_gui_argc = argc;
+ unix_gui_argv = argv;
+}
+
+int target_main_handle_early(int argc, TCHAR **argv)
+{
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+ for (int i = 1; i < argc; i++) {
+ if (!_tcscmp(argv[i], _T("--qt-board-catalog"))) {
+ return runWinUaeQtBoardCatalogDump();
+ }
+ }
+#endif
+ return -1;
+}
+
+int gui_init(void)
+{
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+ const int action = runWinUaeQtLauncherForPrefs(unix_gui_argc, unix_gui_argv, &changed_prefs, 0);
+ if (action == WINUAE_QT_LAUNCHER_START) {
+ return 1;
+ }
+ if (action == WINUAE_QT_LAUNCHER_ERROR) {
+ return -1;
+ }
+ return -2;
+#else
+ return 0;
+#endif
+}
+int gui_update(void) { return 1; }
+void gui_exit(void) {}
+void gui_led(int led, int on, int brightness)
+{
+ if (on >= 0 && led >= 0 && led < int(sizeof(gui_ledstate) * 8)) {
+ if (on) {
+ gui_ledstate |= 1u << led;
+ } else {
+ gui_ledstate &= ~(1u << led);
+ }
+ }
+ if (led == LED_POWER && brightness >= 0) {
+ gui_data.powerled_brightness = brightness;
+ }
+}
+void gui_filename(int, const TCHAR*) {}
+void gui_fps(int fps, int lines, bool lace, int idle, int color)
+{
+ gui_data.fps = fps;
+ gui_data.lines = lines;
+ gui_data.lace = lace;
+ gui_data.idle = idle;
+ gui_data.fps_color = color;
+ gui_led(LED_FPS, 1, -1);
+ gui_led(LED_LINES, 1, -1);
+ gui_led(LED_CPU, 1, -1);
+ gui_led(LED_SND, (gui_data.sndbuf_status > 1 || gui_data.sndbuf_status < 0) ? 0 : 1, -1);
+}
+void gui_lock(void) {}
+void gui_unlock(void) {}
+
+static void gui_flicker_led_single(int led, int status)
+{
+ static int resetcounter[LED_MAX];
+ uae_s8 *target = nullptr;
+
+ if (led == LED_HD) {
+ target = &gui_data.hd;
+ } else if (led == LED_CD) {
+ target = &gui_data.cd;
+ } else if (led == LED_MD) {
+ target = &gui_data.md;
+ } else if (led == LED_NET) {
+ target = &gui_data.net;
+ }
+ if (!target) {
+ return;
+ }
+
+ const uae_s8 old = *target;
+ if (status < 0) {
+ gui_led(led, old < 0 ? -1 : 0, -1);
+ return;
+ }
+ if (status == 0 && old < 0) {
+ *target = 0;
+ resetcounter[led] = 0;
+ gui_led(led, 0, -1);
+ return;
+ }
+ if (status == 0) {
+ resetcounter[led]--;
+ if (resetcounter[led] > 0) {
+ return;
+ }
+ }
+
+ *target = status;
+ resetcounter[led] = 15;
+ if (old != *target) {
+ gui_led(led, *target, -1);
+ }
+}
+
+void gui_flicker_led(int led, int, int status)
+{
+ if (led < 0) {
+ gui_flicker_led_single(LED_HD, 0);
+ gui_flicker_led_single(LED_CD, 0);
+ if (gui_data.net >= 0) {
+ gui_flicker_led_single(LED_NET, 0);
+ }
+ if (gui_data.md >= 0) {
+ gui_flicker_led_single(LED_MD, 0);
+ }
+ } else {
+ gui_flicker_led_single(led, status);
+ }
+}
+void gui_disk_image_change(int, const TCHAR*, bool) {}
+
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+static bool write_runtime_config_snapshot(TCHAR *path, size_t path_len)
+{
+ const char *tmpdir = getenv("TMPDIR");
+ if (!tmpdir || !tmpdir[0]) {
+ tmpdir = "/tmp";
+ }
+ const int written = snprintf(path, path_len, "%s/winuae-runtime-%ld.uae", tmpdir, (long)getpid());
+ if (written < 0 || size_t(written) >= path_len) {
+ write_log("Unix Qt runtime UI: temporary config path is too long\n");
+ return false;
+ }
+ if (!cfgfile_save(&changed_prefs, path, 0)) {
+ write_log("Unix Qt runtime UI: failed to write temporary config '%s'\n", path);
+ return false;
+ }
+ return true;
+}
+
+static const TCHAR *runtime_shortcut_initial_path(int shortcut)
+{
+ if (shortcut >= 0 && shortcut < 4) {
+ return changed_prefs.floppyslots[shortcut].df[0]
+ ? changed_prefs.floppyslots[shortcut].df
+ : currprefs.floppyslots[shortcut].df;
+ }
+ if (shortcut == 4 || shortcut == 5) {
+ if (savestate_fname[0]) {
+ return savestate_fname;
+ }
+ if (changed_prefs.statefile[0]) {
+ return changed_prefs.statefile;
+ }
+ return currprefs.statefile;
+ }
+ if (shortcut == 6) {
+ return changed_prefs.cdslots[0].name[0]
+ ? changed_prefs.cdslots[0].name
+ : currprefs.cdslots[0].name;
+ }
+ return "";
+}
+
+static bool apply_runtime_shortcut_selection(int shortcut, const TCHAR *path)
+{
+ if (!path || !path[0]) {
+ return false;
+ }
+
+ if (shortcut >= 0 && shortcut < 4) {
+ _tcsncpy(changed_prefs.floppyslots[shortcut].df, path, MAX_DPATH);
+ changed_prefs.floppyslots[shortcut].df[MAX_DPATH - 1] = 0;
+ set_config_changed();
+ return true;
+ }
+ if (shortcut == 4) {
+ savestate_initsave(path, 1, true, false);
+ savestate_state = STATE_DORESTORE;
+ return true;
+ }
+ if (shortcut == 5) {
+ savestate_initsave(path, 1, true, true);
+ save_state(savestate_fname, STATE_SAVE_DESCRIPTION);
+ return true;
+ }
+ if (shortcut == 6) {
+ _tcsncpy(changed_prefs.cdslots[0].name, path, MAX_DPATH);
+ changed_prefs.cdslots[0].name[MAX_DPATH - 1] = 0;
+ changed_prefs.cdslots[0].inuse = true;
+ set_config_changed();
+ return true;
+ }
+ return false;
+}
+#endif
+
+void gui_display(int shortcut)
+{
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+ static bool active;
+ if (active) {
+ return;
+ }
+ if (shortcut != -1 && (shortcut < 0 || shortcut > 6)) {
+ write_log("Unix Qt runtime UI: shortcut %d is not implemented yet\n", shortcut);
+ return;
+ }
+
+ active = true;
+
+ const int old_pause = pause_emulation;
+ pause_emulation = 1;
+ setsystime();
+ inputdevice_unacquire();
+ pause_sound();
+
+ if (shortcut == -1) {
+ TCHAR snapshot_path[MAX_DPATH];
+ snapshot_path[0] = 0;
+ const bool have_snapshot = write_runtime_config_snapshot(snapshot_path, sizeof snapshot_path / sizeof snapshot_path[0]);
+
+ int exit_code = 0;
+ const int action = runWinUaeQtLauncherForPrefsWithConfig(
+ unix_gui_argc,
+ unix_gui_argv,
+ &changed_prefs,
+ have_snapshot ? snapshot_path : nullptr,
+ &exit_code);
+
+ if (have_snapshot) {
+ unlink(snapshot_path);
+ }
+
+ if (action == WINUAE_QT_LAUNCHER_START) {
+ fixup_prefs(&changed_prefs, true);
+ reset_sound();
+ inputdevice_copyconfig(&changed_prefs, &currprefs);
+ inputdevice_config_change_test();
+ set_config_changed();
+ } else if (action == WINUAE_QT_LAUNCHER_ERROR) {
+ write_log("Unix Qt runtime UI exited with error code %d\n", exit_code);
+ }
+ } else {
+ TCHAR selected_path[MAX_DPATH];
+ selected_path[0] = 0;
+ int exit_code = 0;
+ const int action = runWinUaeQtRuntimeFileDialog(
+ unix_gui_argc,
+ unix_gui_argv,
+ shortcut,
+ runtime_shortcut_initial_path(shortcut),
+ selected_path,
+ sizeof selected_path / sizeof selected_path[0],
+ &exit_code);
+ if (action == WINUAE_QT_LAUNCHER_START) {
+ apply_runtime_shortcut_selection(shortcut, selected_path);
+ } else if (action == WINUAE_QT_LAUNCHER_ERROR) {
+ write_log("Unix Qt runtime file dialog exited with error code %d\n", exit_code);
+ }
+ }
+
+ pause_emulation = old_pause;
+ setsystime();
+ resume_sound();
+ inputdevice_acquire(TRUE);
+ fpscounter_reset();
+
+ active = false;
+#else
+ write_log("Unix Qt runtime UI is not enabled in this build\n");
+#endif
+}
+void gui_gameport_button_change(int, int, int) {}
+void gui_gameport_axis_change(int, int, int, int) {}
+void notify_user(int msg)
+{
+ switch (msg) {
+ case NUMSG_MODRIP_NOTFOUND:
+ write_log("No music modules or packed data found.\n");
+ break;
+ case NUMSG_MODRIP_FINISHED:
+ write_log("Module ripper scan finished.\n");
+ break;
+ default:
+ write_log("notify_user: %d\n", msg);
+ break;
+ }
+}
+void notify_user_parms(int msg, const TCHAR*, ...) { write_log("notify_user: %d\n", msg); }
+int translate_message(int msg, TCHAR *out)
+{
+ if (!out) {
+ return 0;
+ }
+ switch (msg) {
+ case NUMSG_MODRIP_SAVE:
+ _tcscpy(out, _T("Module/packed data found\n%s\nStart address %08.8X, Size %d bytes\n'%s'\nWould you like to save it?"));
+ return 1;
+ default:
+ out[0] = 0;
+ return 0;
+ }
+}
+void gui_message(const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ fputc('\n', stderr);
+ va_end(ap);
+}
+
+int gui_message_multibutton(int flags, const TCHAR *format, ...)
+{
+ TCHAR msg[2048];
+ va_list ap;
+ va_start(ap, format);
+ _vsntprintf(msg, sizeof msg / sizeof(TCHAR), format, ap);
+ msg[(sizeof msg / sizeof(TCHAR)) - 1] = 0;
+ va_end(ap);
+
+ const size_t msg_len = _tcslen(msg);
+ write_log("%s", msg);
+ if (msg_len == 0 || msg[msg_len - 1] != '\n') {
+ write_log("\n");
+ }
+
+#ifdef WINUAE_UNIX_WITH_INTEGRATED_QT_UI
+ int exit_code = 0;
+ const int ret = runWinUaeQtMessageBox(unix_gui_argc, unix_gui_argv, flags, msg, &exit_code);
+ if (exit_code == 0) {
+ return ret;
+ }
+#endif
+
+ return flags == 0 ? 0 : 1;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#if defined(__APPLE__)
+#include <sys/disk.h>
+#include <sys/ioctl.h>
+#elif defined(__linux__)
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#endif
+
+#include "options.h"
+#include "filesys.h"
+#include "uae.h"
+#include "uae/io.h"
+
+struct hardfilehandle {
+ int fd;
+ bool realdrive;
+};
+
+#define UNIX_MAX_NATIVE_DRIVES MAX_FILESYSTEM_UNITS
+
+struct unix_driveinfo {
+ TCHAR device_name[1024];
+ TCHAR device_path[1024];
+ TCHAR device_full_path[2048];
+ uae_u64 size;
+ int bytespersector;
+ int readonly;
+ int dangerous;
+};
+
+static unix_driveinfo unix_drives[UNIX_MAX_NATIVE_DRIVES];
+static int unix_drive_count;
+
+static bool query_fd_geometry(int fd, uae_u64 *size, int *blocksize)
+{
+ if (size) {
+ *size = 0;
+ }
+ if (blocksize) {
+ *blocksize = 512;
+ }
+#if defined(__APPLE__)
+ uint32_t block_size = 512;
+ uint64_t block_count = 0;
+ if (ioctl(fd, DKIOCGETBLOCKSIZE, &block_size) == 0 && block_size > 0 && blocksize) {
+ *blocksize = (int)block_size;
+ }
+ if (ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count) == 0 && size) {
+ *size = block_count * (uae_u64)(blocksize ? *blocksize : block_size);
+ return *size > 0;
+ }
+#elif defined(__linux__)
+ unsigned long long bytes = 0;
+ int logical_block_size = 512;
+ if (ioctl(fd, BLKSSZGET, &logical_block_size) == 0 && logical_block_size > 0 && blocksize) {
+ *blocksize = logical_block_size;
+ }
+ if (ioctl(fd, BLKGETSIZE64, &bytes) == 0 && size) {
+ *size = (uae_u64)bytes;
+ return *size > 0;
+ }
+#endif
+ struct stat st;
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) && size) {
+ *size = (uae_u64)st.st_size;
+ return true;
+ }
+ return false;
+}
+
+static bool query_path_geometry(const char *path, uae_u64 *size, int *blocksize)
+{
+ int fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ return false;
+ }
+ bool ok = query_fd_geometry(fd, size, blocksize);
+ close(fd);
+ return ok;
+}
+
+static bool unix_drive_path_exists(const char *path)
+{
+ for (int i = 0; i < unix_drive_count; i++) {
+ if (!_tcscmp(unix_drives[i].device_path, path)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void add_unix_drive(const char *path, const char *display_name)
+{
+#ifdef WINUAE_UNIX_WITH_NATIVE_HARDDRIVES
+ if (!path || !path[0] || unix_drive_count >= UNIX_MAX_NATIVE_DRIVES || unix_drive_path_exists(path)) {
+ return;
+ }
+ uae_u64 size = 0;
+ int blocksize = 512;
+ if (!query_path_geometry(path, &size, &blocksize) || size == 0) {
+ return;
+ }
+ unix_driveinfo *udi = &unix_drives[unix_drive_count++];
+ memset(udi, 0, sizeof *udi);
+ _tcsncpy(udi->device_path, path, sizeof udi->device_path / sizeof(TCHAR) - 1);
+ _sntprintf(udi->device_full_path, sizeof udi->device_full_path / sizeof(TCHAR), _T(":%s"), path);
+ _sntprintf(udi->device_name, sizeof udi->device_name / sizeof(TCHAR), _T(":%s"),
+ display_name && display_name[0] ? display_name : path);
+ udi->size = size;
+ udi->bytespersector = blocksize > 0 ? blocksize : 512;
+ udi->readonly = 1;
+ udi->dangerous = 0;
+#else
+ (void)path;
+ (void)display_name;
+#endif
+}
+
+static void enumerate_unix_drives(void)
+{
+ unix_drive_count = 0;
+#ifdef WINUAE_UNIX_WITH_NATIVE_HARDDRIVES
+#if defined(__APPLE__)
+ DIR *dir = opendir("/dev");
+ if (!dir) {
+ return;
+ }
+ for (struct dirent *entry = readdir(dir); entry; entry = readdir(dir)) {
+ const char *name = entry->d_name;
+ if (strncmp(name, "rdisk", 5) != 0) {
+ continue;
+ }
+ if (strchr(name + 5, 's')) {
+ continue;
+ }
+ char path[PATH_MAX];
+ snprintf(path, sizeof path, "/dev/%s", name);
+ add_unix_drive(path, name);
+ }
+ closedir(dir);
+#elif defined(__linux__)
+ DIR *dir = opendir("/sys/block");
+ if (!dir) {
+ return;
+ }
+ for (struct dirent *entry = readdir(dir); entry; entry = readdir(dir)) {
+ const char *name = entry->d_name;
+ if (name[0] == '.') {
+ continue;
+ }
+ if (!strncmp(name, "loop", 4) || !strncmp(name, "ram", 3) || !strncmp(name, "zram", 4) || !strncmp(name, "dm-", 3)) {
+ continue;
+ }
+ char path[PATH_MAX];
+ snprintf(path, sizeof path, "/dev/%s", name);
+ add_unix_drive(path, name);
+ }
+ closedir(dir);
+#endif
+#endif
+}
+
+static bool is_native_device_name(const TCHAR *name)
+{
+ return name && name[0] == ':' && name[1] == '/';
+}
+
+int hdf_init_target(void)
+{
+ enumerate_unix_drives();
+ return 1;
+}
+
+int hdf_open_target(struct hardfiledata *hfd, const TCHAR *name)
+{
+ if (!hfd || !name) {
+ return 0;
+ }
+ hdf_close_target(hfd);
+ hfd->handle = xcalloc(hardfilehandle, 1);
+ hfd->handle->fd = -1;
+ hfd->cache = xcalloc(uae_u8, 16384);
+ hfd->cache_valid = 0;
+ hfd->flags = 0;
+ if (is_native_device_name(name)) {
+#ifdef WINUAE_UNIX_WITH_NATIVE_HARDDRIVES
+ const TCHAR *path = name + 1;
+ int fd = open(path, O_RDONLY | O_CLOEXEC);
+ if (fd < 0) {
+ hdf_close_target(hfd);
+ return 0;
+ }
+ uae_u64 size = 0;
+ int blocksize = hfd->ci.blocksize > 0 ? hfd->ci.blocksize : 512;
+ if (!query_fd_geometry(fd, &size, &blocksize) || size == 0) {
+ close(fd);
+ hdf_close_target(hfd);
+ return 0;
+ }
+ hfd->handle->fd = fd;
+ hfd->handle->realdrive = true;
+ hfd->flags = HFD_FLAGS_REALDRIVE;
+ hfd->ci.readonly = true;
+ hfd->physsize = hfd->virtsize = size;
+ hfd->offset = 0;
+ hfd->handle_valid = 1;
+ hfd->ci.blocksize = blocksize;
+ _tcsncpy(hfd->vendor_id, _T("Unix"), sizeof hfd->vendor_id / sizeof(TCHAR) - 1);
+ _tcsncpy(hfd->product_id, path, sizeof hfd->product_id / sizeof(TCHAR) - 1);
+ return 1;
+#else
+ hdf_close_target(hfd);
+ return 0;
+#endif
+ }
+ int open_flags = hfd->ci.readonly ? O_RDONLY : O_RDWR;
+ hfd->handle->fd = open(name, open_flags | O_CLOEXEC);
+ if (hfd->handle->fd < 0 && !hfd->ci.readonly) {
+ hfd->ci.readonly = true;
+ hfd->handle->fd = open(name, O_RDONLY | O_CLOEXEC);
+ }
+ if (hfd->handle->fd < 0) {
+ hdf_close_target(hfd);
+ return 0;
+ }
+ uae_u64 size = 0;
+ int blocksize = hfd->ci.blocksize > 0 ? hfd->ci.blocksize : 512;
+ if (!query_fd_geometry(hfd->handle->fd, &size, &blocksize)) {
+ hdf_close_target(hfd);
+ return 0;
+ }
+ hfd->physsize = hfd->virtsize = size;
+ hfd->offset = 0;
+ hfd->handle_valid = 1;
+ if (hfd->ci.blocksize <= 0) {
+ hfd->ci.blocksize = blocksize > 0 ? blocksize : 512;
+ }
+ return 1;
+}
+
+int hdf_dup_target(struct hardfiledata *dhfd, const struct hardfiledata *shfd)
+{
+ if (!dhfd || !shfd) {
+ return 0;
+ }
+ *dhfd = *shfd;
+ dhfd->handle = NULL;
+ dhfd->cache = NULL;
+ return hdf_open_target(dhfd, shfd->ci.rootdir);
+}
+
+void hdf_close_target(struct hardfiledata *hfd)
+{
+ if (!hfd) {
+ return;
+ }
+ if (hfd->handle) {
+ if (hfd->handle->fd >= 0) {
+ close(hfd->handle->fd);
+ }
+ xfree(hfd->handle);
+ hfd->handle = NULL;
+ }
+ xfree(hfd->cache);
+ hfd->cache = NULL;
+ hfd->cache_valid = 0;
+ hfd->handle_valid = 0;
+}
+
+int hdf_read_target(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len, uae_u32 *error)
+{
+ if (error) {
+ *error = 0;
+ }
+ if (!hfd || !hfd->handle || hfd->handle->fd < 0) {
+ if (error) {
+ *error = errno;
+ }
+ return 0;
+ }
+ ssize_t got = pread(hfd->handle->fd, buffer, len, (off_t)(offset + hfd->offset));
+ if (got < 0) {
+ if (error) {
+ *error = errno;
+ }
+ return 0;
+ }
+ return (int)got;
+}
+
+int hdf_write_target(struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len, uae_u32 *error)
+{
+ if (error) {
+ *error = 0;
+ }
+ if (!hfd || hfd->ci.readonly || !hfd->handle || hfd->handle->fd < 0 || hfd->handle->realdrive) {
+ if (error) {
+ *error = errno ? errno : EACCES;
+ }
+ return 0;
+ }
+ ssize_t done = pwrite(hfd->handle->fd, buffer, len, (off_t)(offset + hfd->offset));
+ if (done < 0) {
+ if (error) {
+ *error = errno;
+ }
+ return 0;
+ }
+ return (int)done;
+}
+
+int hdf_resize_target(struct hardfiledata *hfd, uae_u64 newsize)
+{
+ if (!hfd || !hfd->handle || hfd->handle->fd < 0 || hfd->handle->realdrive) {
+ return 0;
+ }
+ if (ftruncate(hfd->handle->fd, (off_t)newsize) != 0) {
+ return 0;
+ }
+ hfd->physsize = hfd->virtsize = newsize;
+ return 1;
+}
+
+int hdf_getnumharddrives(void)
+{
+ if (unix_drive_count == 0) {
+ enumerate_unix_drives();
+ }
+ return unix_drive_count;
+}
+
+TCHAR *hdf_getnameharddrive(int index, int flags, int *sectorsize, int *dangerousdrive, uae_u32 *outflags)
+{
+ static TCHAR name[2048];
+ if (sectorsize) {
+ *sectorsize = 512;
+ }
+ if (dangerousdrive) {
+ *dangerousdrive = 0;
+ }
+ if (outflags) {
+ *outflags = 0;
+ }
+ if (index < 0 || index >= hdf_getnumharddrives()) {
+ name[0] = 0;
+ return name;
+ }
+ unix_driveinfo *udi = &unix_drives[index];
+ if (sectorsize) {
+ *sectorsize = udi->bytespersector;
+ }
+ if (dangerousdrive) {
+ *dangerousdrive = udi->dangerous ? 0 : 1;
+ if (udi->readonly) {
+ *dangerousdrive |= 2;
+ }
+ }
+ if (flags & 4) {
+ return udi->device_full_path;
+ }
+ if (flags & 2) {
+ return udi->device_path;
+ }
+ if (flags & 1) {
+ TCHAR size_text[32];
+ if (udi->size >= 1024ULL * 1024ULL * 1024ULL) {
+ _sntprintf(size_text, sizeof size_text / sizeof(TCHAR), _T("%.1fG"), (double)udi->size / (1024.0 * 1024.0 * 1024.0));
+ } else if (udi->size >= 1024ULL * 1024ULL) {
+ _sntprintf(size_text, sizeof size_text / sizeof(TCHAR), _T("%.1fM"), (double)udi->size / (1024.0 * 1024.0));
+ } else {
+ _sntprintf(size_text, sizeof size_text / sizeof(TCHAR), _T("%lluK"), (unsigned long long)(udi->size / 1024));
+ }
+ _sntprintf(name, sizeof name / sizeof(TCHAR), _T("%10s [%s,RO] %s"), _T("[OS]"), size_text, udi->device_name + 1);
+ return name;
+ }
+ return udi->device_name;
+}
+
+int get_guid_target(uae_u8 *out)
+{
+ if (!out) {
+ return 0;
+ }
+ for (int i = 0; i < 16; i++) {
+ out[i] = (uae_u8)uaerand();
+ }
+ return 1;
+}
--- /dev/null
+#ifndef WINUAE_OD_UNIX_HOST_H
+#define WINUAE_OD_UNIX_HOST_H
+
+bool unix_host_quit_requested(void);
+void unix_host_check_quit(void);
+
+#endif /* WINUAE_OD_UNIX_HOST_H */
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "uae.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <mutex>
+#include <string>
+#include <vector>
+
+int console_logging;
+int always_flush_log;
+TCHAR *conlogfile;
+FILE *debugfile;
+
+static constexpr size_t LOG_CAPTURE_LIMIT = 256 * 1024;
+
+static std::mutex log_capture_mutex;
+static std::string log_capture;
+
+static void capture_log_bytes(const char *text, size_t len)
+{
+ if (!text || len == 0) {
+ return;
+ }
+ std::lock_guard<std::mutex> lock(log_capture_mutex);
+ if (len >= LOG_CAPTURE_LIMIT) {
+ log_capture.assign(text + len - LOG_CAPTURE_LIMIT, LOG_CAPTURE_LIMIT);
+ return;
+ }
+ if (log_capture.size() + len > LOG_CAPTURE_LIMIT) {
+ log_capture.erase(0, log_capture.size() + len - LOG_CAPTURE_LIMIT);
+ }
+ log_capture.append(text, len);
+}
+
+static void capture_log_format(const char *format, va_list ap)
+{
+ va_list size_args;
+ va_copy(size_args, ap);
+ const int needed = vsnprintf(NULL, 0, format, size_args);
+ va_end(size_args);
+ if (needed <= 0) {
+ return;
+ }
+
+ std::vector<char> buffer(size_t(needed) + 1);
+ va_list format_args;
+ va_copy(format_args, ap);
+ vsnprintf(buffer.data(), buffer.size(), format, format_args);
+ va_end(format_args);
+ capture_log_bytes(buffer.data(), size_t(needed));
+}
+
+static void vlog_write(const char *format, va_list ap)
+{
+ va_list stderr_args;
+ va_copy(stderr_args, ap);
+ vfprintf(stderr, format, stderr_args);
+ va_end(stderr_args);
+ fflush(stderr);
+
+ if (debugfile) {
+ va_list file_args;
+ va_copy(file_args, ap);
+ vfprintf(debugfile, format, file_args);
+ va_end(file_args);
+ if (always_flush_log) {
+ fflush(debugfile);
+ }
+ }
+
+ capture_log_format(format, ap);
+}
+
+void write_log(const char *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_write(format, ap);
+ va_end(ap);
+}
+
+void write_logx(const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_write(format, ap);
+ va_end(ap);
+}
+
+void write_dlog(const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_write(format, ap);
+ va_end(ap);
+}
+
+int read_log(void)
+{
+ return 0;
+}
+
+void flush_log(void)
+{
+ fflush(stderr);
+ if (debugfile) {
+ fflush(debugfile);
+ }
+}
+
+void logging_init(void)
+{
+}
+
+uae_u8 *save_log(int, size_t *len)
+{
+ if (!len) {
+ return NULL;
+ }
+
+ flush_log();
+
+ std::lock_guard<std::mutex> lock(log_capture_mutex);
+ size_t size = log_capture.size();
+ size_t offset = 0;
+ if (*len > 0 && size > *len) {
+ offset = size - *len;
+ size = *len;
+ }
+ if (size == 0) {
+ *len = 0;
+ return NULL;
+ }
+
+ uae_u8 *dst = xmalloc(uae_u8, size + 1);
+ if (!dst) {
+ *len = 0;
+ return NULL;
+ }
+ memcpy(dst, log_capture.data() + offset, size);
+ dst[size] = 0;
+ *len = size + 1;
+ return dst;
+}
+
+FILE *log_open(const TCHAR *name, int append, int, TCHAR*)
+{
+ return fopen(name, append ? "ab" : "wb");
+}
+
+void log_close(FILE *f)
+{
+ if (f) {
+ if (f == debugfile) {
+ debugfile = NULL;
+ }
+ fclose(f);
+ }
+}
+
+TCHAR *setconsolemode(TCHAR *buffer, int)
+{
+ return buffer;
+}
+
+void close_console(void) {}
+void open_console(void) {}
+bool is_interactive_console(void) { return true; }
+void reopen_console(void) {}
+void activate_console(void) {}
+void deactivate_console(void) {}
+void set_console_input_mode(int) {}
+bool is_console_open(void) { return true; }
+void console_out(const TCHAR *s)
+{
+ fputs(s, stderr);
+ if (debugfile) {
+ fputs(s, debugfile);
+ if (always_flush_log) {
+ fflush(debugfile);
+ }
+ }
+ capture_log_bytes(s, strlen(s));
+}
+void console_out_f(const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_write(format, ap);
+ va_end(ap);
+}
+void console_flush(void) { flush_log(); }
+int console_get(TCHAR *, int) { return 0; }
+bool console_isch(void) { return false; }
+TCHAR console_getch(void) { return 0; }
+
+void jit_abort(const char *format, ...)
+{
+ char buffer[4096];
+
+ va_list ap;
+ va_start(ap, format);
+ vsnprintf(buffer, sizeof(buffer), format, ap);
+ va_end(ap);
+ buffer[sizeof(buffer) - 1] = 0;
+
+ write_log("JIT: Serious error: %s\n", buffer);
+ uae_reset(1, 0);
+}
+
+void f_out(void *, const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ vlog_write(format, ap);
+ va_end(ap);
+}
+TCHAR* buf_out(TCHAR *buffer, int *bufsize, const TCHAR *format, ...)
+{
+ va_list ap;
+ va_start(ap, format);
+ int n = vsnprintf(buffer, *bufsize, format, ap);
+ va_end(ap);
+ if (n >= 0 && n < *bufsize) {
+ *bufsize -= n;
+ return buffer + n;
+ }
+ return buffer;
+}
+TCHAR *write_log_get_ts(void)
+{
+ static TCHAR ts[1] = { 0 };
+ return ts;
+}
--- /dev/null
+#ifndef WINUAE_OD_UNIX_MACHDEP_M68K_H
+#define WINUAE_OD_UNIX_MACHDEP_M68K_H
+
+#include <stdlib.h>
+#include "uae/types.h"
+
+struct flag_struct {
+#if defined(CPU_AARCH64)
+ union {
+ uae_u64 cznv;
+ uae_u64 nzcv;
+ };
+ uae_u64 x;
+#else
+ uae_u32 cznv;
+ uae_u32 x;
+#endif
+};
+
+extern struct flag_struct regflags;
+
+#if defined(CPU_AARCH64)
+#define FLAGBIT_N 31
+#define FLAGBIT_Z 30
+#define FLAGBIT_C 29
+#define FLAGBIT_V 28
+#define FLAGBIT_X 0
+
+#define FLAGVAL_N (1UL << FLAGBIT_N)
+#define FLAGVAL_Z (1UL << FLAGBIT_Z)
+#define FLAGVAL_C (1UL << FLAGBIT_C)
+#define FLAGVAL_V (1UL << FLAGBIT_V)
+#define FLAGVAL_X (1UL << FLAGBIT_X)
+
+#define SET_ZFLG(y) (regflags.nzcv = (regflags.nzcv & ~FLAGVAL_Z) | (((y) ? 1UL : 0UL) << FLAGBIT_Z))
+#define SET_CFLG(y) (regflags.nzcv = (regflags.nzcv & ~FLAGVAL_C) | (((y) ? 1UL : 0UL) << FLAGBIT_C))
+#define SET_VFLG(y) (regflags.nzcv = (regflags.nzcv & ~FLAGVAL_V) | (((y) ? 1UL : 0UL) << FLAGBIT_V))
+#define SET_NFLG(y) (regflags.nzcv = (regflags.nzcv & ~FLAGVAL_N) | (((y) ? 1UL : 0UL) << FLAGBIT_N))
+#define SET_XFLG(y) (regflags.x = ((y) ? 1UL : 0UL))
+
+#define GET_ZFLG() ((regflags.nzcv >> FLAGBIT_Z) & 1)
+#define GET_CFLG() ((regflags.nzcv >> FLAGBIT_C) & 1)
+#define GET_VFLG() ((regflags.nzcv >> FLAGBIT_V) & 1)
+#define GET_NFLG() ((regflags.nzcv >> FLAGBIT_N) & 1)
+#define GET_XFLG() (regflags.x & 1)
+
+#define CLEAR_CZNV() (regflags.nzcv = 0)
+#define GET_CZNV() (regflags.nzcv)
+#define IOR_CZNV(X) (regflags.nzcv |= (X))
+#define SET_CZNV(X) (regflags.nzcv = (X))
+#define COPY_CARRY() (regflags.x = (regflags.nzcv >> FLAGBIT_C) & 1)
+#else
+#define FLAGBIT_N 15
+#define FLAGBIT_Z 14
+#define FLAGBIT_C 8
+#define FLAGBIT_V 0
+#define FLAGBIT_X 8
+
+#define FLAGVAL_N (1 << FLAGBIT_N)
+#define FLAGVAL_Z (1 << FLAGBIT_Z)
+#define FLAGVAL_C (1 << FLAGBIT_C)
+#define FLAGVAL_V (1 << FLAGBIT_V)
+#define FLAGVAL_X (1 << FLAGBIT_X)
+
+#define SET_ZFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_Z) | (((y) ? 1 : 0) << FLAGBIT_Z))
+#define SET_CFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_C) | (((y) ? 1 : 0) << FLAGBIT_C))
+#define SET_VFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_V) | (((y) ? 1 : 0) << FLAGBIT_V))
+#define SET_NFLG(y) (regflags.cznv = (regflags.cznv & ~FLAGVAL_N) | (((y) ? 1 : 0) << FLAGBIT_N))
+#define SET_XFLG(y) (regflags.x = ((y) ? 1 : 0) << FLAGBIT_X)
+
+#define GET_ZFLG() ((regflags.cznv >> FLAGBIT_Z) & 1)
+#define GET_CFLG() ((regflags.cznv >> FLAGBIT_C) & 1)
+#define GET_VFLG() ((regflags.cznv >> FLAGBIT_V) & 1)
+#define GET_NFLG() ((regflags.cznv >> FLAGBIT_N) & 1)
+#define GET_XFLG() ((regflags.x >> FLAGBIT_X) & 1)
+
+#define CLEAR_CZNV() (regflags.cznv = 0)
+#define GET_CZNV() (regflags.cznv)
+#define IOR_CZNV(X) (regflags.cznv |= (X))
+#define SET_CZNV(X) (regflags.cznv = (X))
+#define COPY_CARRY() (regflags.x = regflags.cznv)
+#endif
+
+static inline int cctrue(int cc)
+{
+ uae_u64 cznv = GET_CZNV();
+ switch (cc) {
+ case 0: return 1;
+ case 1: return 0;
+ case 2: return (cznv & (FLAGVAL_C | FLAGVAL_Z)) == 0;
+ case 3: return (cznv & (FLAGVAL_C | FLAGVAL_Z)) != 0;
+ case 4: return (cznv & FLAGVAL_C) == 0;
+ case 5: return (cznv & FLAGVAL_C) != 0;
+ case 6: return (cznv & FLAGVAL_Z) == 0;
+ case 7: return (cznv & FLAGVAL_Z) != 0;
+ case 8: return (cznv & FLAGVAL_V) == 0;
+ case 9: return (cznv & FLAGVAL_V) != 0;
+ case 10: return (cznv & FLAGVAL_N) == 0;
+ case 11: return (cznv & FLAGVAL_N) != 0;
+ case 12: return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & FLAGVAL_N) == 0;
+ case 13: return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & FLAGVAL_N) != 0;
+ case 14:
+ cznv &= (FLAGVAL_N | FLAGVAL_Z | FLAGVAL_V);
+ return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & (FLAGVAL_N | FLAGVAL_Z)) == 0;
+ case 15:
+ cznv &= (FLAGVAL_N | FLAGVAL_Z | FLAGVAL_V);
+ return (((cznv << (FLAGBIT_N - FLAGBIT_V)) ^ cznv) & (FLAGVAL_N | FLAGVAL_Z)) != 0;
+ }
+ abort();
+}
+
+#endif /* WINUAE_OD_UNIX_MACHDEP_M68K_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_MACHDEP_MACCESS_H
+#define WINUAE_OD_UNIX_MACHDEP_MACCESS_H
+
+#include "uae/types.h"
+
+static inline uae_u16 uae_bswap16(uae_u16 v)
+{
+ return __builtin_bswap16(v);
+}
+
+static inline uae_u32 uae_bswap32(uae_u32 v)
+{
+ return __builtin_bswap32(v);
+}
+
+static inline uae_u64 uae_bswap64(uae_u64 v)
+{
+ return __builtin_bswap64(v);
+}
+
+static inline uae_u8 do_get_mem_byte(uae_u8 *a)
+{
+ return *a;
+}
+
+static inline uae_u16 do_get_mem_word(uae_u16 *a)
+{
+ uae_u16 v;
+ __builtin_memcpy(&v, a, sizeof(v));
+ return uae_bswap16(v);
+}
+
+static inline uae_u32 do_get_mem_long(uae_u32 *a)
+{
+ uae_u32 v;
+ __builtin_memcpy(&v, a, sizeof(v));
+ return uae_bswap32(v);
+}
+
+static inline uae_u64 do_get_mem_quad(uae_u64 *a)
+{
+ uae_u64 v;
+ __builtin_memcpy(&v, a, sizeof(v));
+ return uae_bswap64(v);
+}
+
+static inline void do_put_mem_byte(uae_u8 *a, uae_u8 v)
+{
+ *a = v;
+}
+
+static inline void do_put_mem_word(uae_u16 *a, uae_u16 v)
+{
+ v = uae_bswap16(v);
+ __builtin_memcpy(a, &v, sizeof(v));
+}
+
+static inline void do_put_mem_long(uae_u32 *a, uae_u32 v)
+{
+ v = uae_bswap32(v);
+ __builtin_memcpy(a, &v, sizeof(v));
+}
+
+static inline void do_put_mem_quad(uae_u64 *a, uae_u64 v)
+{
+ v = uae_bswap64(v);
+ __builtin_memcpy(a, &v, sizeof(v));
+}
+
+static inline uae_u16 do_byteswap_16(uae_u16 v) { return uae_bswap16(v); }
+static inline uae_u32 do_byteswap_32(uae_u32 v) { return uae_bswap32(v); }
+static inline uae_u64 do_byteswap_64(uae_u64 v) { return uae_bswap64(v); }
+
+static inline uae_u32 do_get_mem_word_unswapped(uae_u16 *a)
+{
+ return *a;
+}
+
+#define ALIGN_POINTER_TO32(p) ((~(uintptr_t)(p)) & 3)
+#define call_mem_get_func(func, addr) ((*func)(addr))
+#define call_mem_put_func(func, addr, v) ((*func)(addr, v))
+
+#endif /* WINUAE_OD_UNIX_MACHDEP_MACCESS_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_MACHDEP_H
+#define WINUAE_OD_UNIX_MACHDEP_H
+
+#if defined(__x86_64__) || defined(__i386__)
+#define MACHDEP_X86 1
+#define MACHDEP_NAME "x86"
+#elif defined(__aarch64__) || defined(__arm__)
+#define MACHDEP_ARM 1
+#define MACHDEP_NAME "arm"
+#else
+#define MACHDEP_NAME "generic"
+#endif
+
+#define HAVE_MACHDEP_TIMER 1
+
+#endif /* WINUAE_OD_UNIX_MACHDEP_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_MACHDEP_RPT_H
+#define WINUAE_OD_UNIX_MACHDEP_RPT_H
+
+#include "uae/time.h"
+
+#endif /* WINUAE_OD_UNIX_MACHDEP_RPT_H */
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "memory.h"
+#include "uae/mman.h"
+
+bool jit_direct_compatible_memory;
+size_t max_z3fastmem = 256 * 1024 * 1024;
+size_t max_physmem = 512 * 1024 * 1024;
+
+bool preinit_shm(void)
+{
+ return true;
+}
+
+bool init_shm(void)
+{
+ jit_direct_compatible_memory = false;
+ canbang = false;
+ return true;
+}
+
+void free_shm(void)
+{
+}
+
+bool uae_mman_info(addrbank *, struct uae_mman_data *)
+{
+ return false;
+}
+
+void mapped_free(addrbank *ab)
+{
+ if (!ab) {
+ return;
+ }
+ if (!(ab->flags & ABFLAG_NOALLOC)) {
+ xfree(ab->baseaddr);
+ }
+ ab->flags &= ~(ABFLAG_MAPPED | ABFLAG_DIRECTMAP);
+ ab->allocated_size = 0;
+ ab->baseaddr = NULL;
+ ab->baseaddr_direct_r = NULL;
+ ab->baseaddr_direct_w = NULL;
+}
+
+void mman_set_barriers(bool)
+{
+}
+
+void commit_natmem_gaps(void)
+{
+}
+
+void *uae_shmat(addrbank *, int, void *, int, struct uae_mman_data *)
+{
+ return (void *)-1;
+}
+
+int uae_shmdt(const void *)
+{
+ return 0;
+}
+
+int uae_shmget(uae_key_t, addrbank *, int)
+{
+ return -1;
+}
+
+int uae_shmctl(int, int, struct uae_shmid_ds *)
+{
+ return 0;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <cstdlib>
+#include <limits.h>
+#include <string>
+#include <string.h>
+#include <unistd.h>
+#include <vector>
+
+#include "path_expand.h"
+
+std::string unix_expand_path(const std::string &path)
+{
+ std::string out;
+ const char *home = getenv("HOME");
+
+ if (!path.empty() && path[0] == '~' && (path.size() == 1 || path[1] == '/')) {
+ out = home ? home : "";
+ out += path.substr(1);
+ } else {
+ out = path;
+ }
+
+ if (home) {
+ std::string homestr(home);
+ size_t slash = homestr.find_last_of('/');
+ std::string user = slash == std::string::npos ? homestr : homestr.substr(slash + 1);
+ std::string oldhome = "/home/" + user;
+ if (!user.empty() && out.compare(0, oldhome.size(), oldhome) == 0 &&
+ (out.size() == oldhome.size() || out[oldhome.size()] == '/')) {
+ out = homestr + out.substr(oldhome.size());
+ }
+ }
+
+ for (size_t i = 0; i < out.size(); i++) {
+ if (out[i] != '$') {
+ continue;
+ }
+ size_t start = i + 1;
+ size_t end = start;
+ std::string name;
+ if (start < out.size() && out[start] == '{') {
+ start++;
+ end = out.find('}', start);
+ if (end == std::string::npos) {
+ continue;
+ }
+ name = out.substr(start, end - start);
+ end++;
+ } else {
+ while (end < out.size() && (isalnum((unsigned char)out[end]) || out[end] == '_')) {
+ end++;
+ }
+ name = out.substr(start, end - start);
+ }
+ if (name.empty()) {
+ continue;
+ }
+ const char *value = getenv(name.c_str());
+ if (!value) {
+ continue;
+ }
+ const size_t value_len = strlen(value);
+ out.replace(i, end - i, value);
+ if (value_len > 0) {
+ i += value_len - 1;
+ }
+ }
+
+ return out;
+}
+
+static bool unix_path_is_absolute(const std::string &path)
+{
+ return !path.empty() && path[0] == '/';
+}
+
+static bool unix_path_has_unresolved_prefix(const std::string &path)
+{
+ return path.find('$') != std::string::npos || (!path.empty() && path[0] == '~');
+}
+
+static std::string unix_join_path(const std::string &dir, const std::string &name)
+{
+ if (dir.empty() || dir == ".") {
+ return name;
+ }
+ if (!dir.empty() && dir[dir.size() - 1] == '/') {
+ return dir + name;
+ }
+ return dir + "/" + name;
+}
+
+static std::string unix_current_directory()
+{
+ char cwd[PATH_MAX];
+ if (getcwd(cwd, sizeof cwd)) {
+ return cwd;
+ }
+ return ".";
+}
+
+static std::string unix_lexically_normalize_absolute(const std::string &path)
+{
+ std::vector<std::string> parts;
+ size_t pos = 0;
+ while (pos < path.size()) {
+ while (pos < path.size() && path[pos] == '/') {
+ pos++;
+ }
+ size_t end = pos;
+ while (end < path.size() && path[end] != '/') {
+ end++;
+ }
+ std::string part = path.substr(pos, end - pos);
+ if (part == "..") {
+ if (!parts.empty()) {
+ parts.pop_back();
+ }
+ } else if (!part.empty() && part != ".") {
+ parts.push_back(part);
+ }
+ pos = end;
+ }
+
+ std::string out = "/";
+ for (size_t i = 0; i < parts.size(); i++) {
+ if (i > 0) {
+ out += "/";
+ }
+ out += parts[i];
+ }
+ return out;
+}
+
+std::string unix_absolute_path(const std::string &path, const std::string &base)
+{
+ if (path.empty() || unix_path_has_unresolved_prefix(path)) {
+ return path;
+ }
+
+ std::string base_path = base.empty() ? unix_current_directory() : base;
+ if (!unix_path_is_absolute(base_path)) {
+ base_path = unix_join_path(unix_current_directory(), base_path);
+ }
+
+ const std::string combined = unix_path_is_absolute(path) ? path : unix_join_path(base_path, path);
+ char resolved[PATH_MAX];
+ if (realpath(combined.c_str(), resolved)) {
+ return resolved;
+ }
+ return unix_lexically_normalize_absolute(combined);
+}
--- /dev/null
+#ifndef WINUAE_OD_UNIX_PATH_EXPAND_H
+#define WINUAE_OD_UNIX_PATH_EXPAND_H
+
+#include <string>
+
+std::string unix_expand_path(const std::string &path);
+std::string unix_absolute_path(const std::string &path, const std::string &base = std::string());
+
+#endif /* WINUAE_OD_UNIX_PATH_EXPAND_H */
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+
+#include "path_expand.h"
+
+static bool require_equal(const char *label, const std::string &actual, const std::string &expected)
+{
+ if (actual == expected) {
+ return true;
+ }
+ fprintf(stderr, "%s: expected '%s', got '%s'\n", label, expected.c_str(), actual.c_str());
+ return false;
+}
+
+int main()
+{
+ bool ok = true;
+ setenv("HOME", "/tmp/winuae-home", 1);
+ setenv("WINUAE_TEST_PATH", "/tmp/winuae-env", 1);
+ setenv("WINUAE_TEST_SUFFIX", "-suffix", 1);
+ unsetenv("WINUAE_TEST_MISSING");
+
+ ok = require_equal("home directory", unix_expand_path("~"), "/tmp/winuae-home") && ok;
+ ok = require_equal("home subpath", unix_expand_path("~/roms/kick.rom"), "/tmp/winuae-home/roms/kick.rom") && ok;
+ ok = require_equal("plain environment", unix_expand_path("$WINUAE_TEST_PATH/kick.rom"), "/tmp/winuae-env/kick.rom") && ok;
+ ok = require_equal("braced environment", unix_expand_path("${WINUAE_TEST_PATH}/kick.rom"), "/tmp/winuae-env/kick.rom") && ok;
+ ok = require_equal("adjacent environment", unix_expand_path("$WINUAE_TEST_PATH${WINUAE_TEST_SUFFIX}"), "/tmp/winuae-env-suffix") && ok;
+ ok = require_equal("embedded environment", unix_expand_path("/roms/$WINUAE_TEST_PATH"), "/roms//tmp/winuae-env") && ok;
+ ok = require_equal("missing environment", unix_expand_path("$WINUAE_TEST_MISSING/kick.rom"), "$WINUAE_TEST_MISSING/kick.rom") && ok;
+ ok = require_equal("malformed brace", unix_expand_path("${WINUAE_TEST_PATH/kick.rom"), "${WINUAE_TEST_PATH/kick.rom") && ok;
+ ok = require_equal("literal dollar", unix_expand_path("disk$"), "disk$") && ok;
+ ok = require_equal("legacy linux home", unix_expand_path("/home/winuae-home/roms"), "/tmp/winuae-home/roms") && ok;
+ ok = require_equal("named home unsupported", unix_expand_path("~other/roms"), "~other/roms") && ok;
+ ok = require_equal("relative absolute path", unix_absolute_path("roms/kick.rom", "/tmp/winuae-base"), "/tmp/winuae-base/roms/kick.rom") && ok;
+ ok = require_equal("relative parent normalization", unix_absolute_path("../disk.adf", "/tmp/winuae-base/configs"), "/tmp/winuae-base/disk.adf") && ok;
+ ok = require_equal("absolute normalization", unix_absolute_path("/tmp/winuae-base/../disk.adf"), "/tmp/disk.adf") && ok;
+ ok = require_equal("unresolved environment absolute path", unix_absolute_path("$WINUAE_TEST_MISSING/kick.rom", "/tmp/winuae-base"), "$WINUAE_TEST_MISSING/kick.rom") && ok;
+ ok = require_equal("unresolved named home absolute path", unix_absolute_path("~other/roms", "/tmp/winuae-base"), "~other/roms") && ok;
+
+ return ok ? 0 : 1;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "options.h"
+#include "traps.h"
+#include "memory.h"
+#include "autoconf.h"
+#include "audio.h"
+#include "cpuboard.h"
+#include "debug.h"
+#include "filesys.h"
+#include "fsdb.h"
+#include "gfxboard.h"
+#include "inputdevice.h"
+#include "keyboard.h"
+#include "rommgr.h"
+#include "savestate.h"
+#include "sampler.h"
+#include "sana2.h"
+#include "scsidev.h"
+#include "statusline.h"
+#include "ethernet.h"
+#include "uae/string.h"
+#include "videograb.h"
+#include "zfile.h"
+#include "zarchive.h"
+
+int consoleopen;
+int log_scsi;
+int log_net;
+int log_vsync;
+int debug_vsync_min_delay;
+int debug_vsync_forced_delay;
+int uaelib_debug;
+int pissoff_value = 15000 * CYCLE_UNIT;
+int multithread_enabled = 1;
+int p96syncrate = 312;
+int p96refresh_active;
+int max_uae_width = 8192;
+int max_uae_height = 8192;
+int pissoff_nojit_value = 160 * CYCLE_UNIT;
+#ifndef BSDSOCKET
+volatile int bsd_int_requested;
+#endif
+
+void machdep_free(void) {}
+void protect_roms(bool) {}
+void debugger_change(int) {}
+void pausevideograb(int) {}
+bool getpausevideograb(void) { return false; }
+uae_s64 getsetpositionvideograb(uae_s64) { return -1; }
+#ifndef WINUAE_UNIX_WITH_SAMPLER
+int sampler_init(void) { return 0; }
+void sampler_free(void) {}
+void sampler_vsync(void) {}
+uae_u8 sampler_getsample(int) { return 0; }
+float sampler_evtime;
+int unix_sampler_device_count(void) { return 0; }
+const TCHAR *unix_sampler_device_name(int) { return _T(""); }
+const TCHAR *unix_sampler_device_config_name(int) { return _T(""); }
+int unix_sampler_device_index_from_config_name(const TCHAR *) { return -1; }
+#endif
+int audio_is_pull(void) { return 0; }
+bool audio_is_pull_event(void) { return false; }
+int audio_pull_buffer(void) { return 0; }
+bool audio_finish_pull(void) { return false; }
+void save_log_open(void) {}
+void update_debug_info(void) {}
+void statusline_updated(int) {}
+#ifndef BSDSOCKET
+void bsdsock_fake_int_handler(void) { bsd_int_requested = 0; }
+#endif
+
+#ifndef GFXBOARD
+void gfxboard_vsync_handler(bool, bool) {}
+#endif
+
+void ldp_render(const char *, int, uae_u8 *, struct vidbuffer *, int, int, int, int)
+{
+}
+
+#ifndef WITH_CPUBOARD
+bool cpuboard_autoconfig_init(struct autoconfig_info *) { return false; }
+bool cpuboard_maprom(void) { return false; }
+void cpuboard_map(void) {}
+void cpuboard_reset(int) {}
+void cpuboard_rethink(void) {}
+void cpuboard_cleanup(void) {}
+void cpuboard_init(void) {}
+void cpuboard_clear(void) {}
+int cpuboard_memorytype(struct uae_prefs *) { return 0; }
+int cpuboard_maxmemory(struct uae_prefs *) { return 0; }
+bool cpuboard_32bit(struct uae_prefs *) { return false; }
+bool cpuboard_io_special(int, uae_u32 *, int, bool) { return false; }
+void cpuboard_overlay_override(void) {}
+uaecptr cpuboard_get_reset_pc(uaecptr *) { return 0; }
+void cpuboard_set_flash_unlocked(bool) {}
+bool cpuboard_forced_hardreset(void) { return false; }
+bool cpuboard_fc_check(uaecptr, uae_u32 *, int, bool) { return false; }
+void cpuboard_gvpmaprom(int) {}
+#endif
+void unprotect_maprom(void) {}
+#ifndef WITH_CPUBOARD
+void cyberstorm_scsi_ram_put(uaecptr, uae_u32) {}
+uae_u32 cyberstorm_scsi_ram_get(uaecptr) { return 0; }
+int REGPARAM2 cyberstorm_scsi_ram_check(uaecptr, uae_u32) { return 0; }
+uae_u8 *REGPARAM2 cyberstorm_scsi_ram_xlate(uaecptr) { return NULL; }
+void cyberstorm_mk3_ppc_irq(int, int) {}
+void blizzardppc_irq(int, int) {}
+void cyberstorm_mk3_ppc_irq_setonly(int, int) {}
+#endif
+#ifndef WITH_PCI
+void wildfire_ncr815_irq(int, int) {}
+#endif
+
+struct netdriverdata **target_ethernet_enumerate(void)
+{
+#if defined(WITH_SLIRP) || defined(WITH_UAENET_PCAP)
+ static netdriverdata *drivers[MAX_TOTAL_NET_DEVICES];
+ memset(drivers, 0, sizeof drivers);
+ ethernet_enumerate(drivers, 0);
+ return drivers;
+#else
+ static netdriverdata *none[1] = { NULL };
+ return none;
+#endif
+}
+
+#ifndef WITH_UAENET_PCAP
+void ethernet_pause(int) {}
+void ethernet_reset(void) {}
+#endif
+
+#ifndef WITH_PCI
+bool ariadne2_init(struct autoconfig_info *) { return false; }
+bool hydra_init(struct autoconfig_info *) { return false; }
+bool lanrover_init(struct autoconfig_info *) { return false; }
+bool xsurf_init(struct autoconfig_info *) { return false; }
+bool xsurf100_init(struct autoconfig_info *) { return false; }
+#endif
+
+#ifndef WINUAE_UNIX_WITH_ARCHIVES
+struct zvolume *archive_directory_plain(struct zfile *) { return NULL; }
+struct zvolume *archive_directory_lha(struct zfile *) { return NULL; }
+struct zvolume *archive_directory_zip(struct zfile *) { return NULL; }
+struct zvolume *archive_directory_7z(struct zfile *) { return NULL; }
+struct zfile *archive_access_7z(struct znode *) { return NULL; }
+struct zvolume *archive_directory_rar(struct zfile *) { return NULL; }
+struct zfile *archive_access_rar(struct znode *) { return NULL; }
+struct zvolume *archive_directory_lzx(struct zfile *) { return NULL; }
+struct zfile *archive_access_lzx(struct znode *) { return NULL; }
+struct zvolume *archive_directory_arcacc(struct zfile *, unsigned int) { return NULL; }
+struct zvolume *archive_directory_adf(struct znode *, struct zfile *) { return NULL; }
+struct zvolume *archive_directory_rdb(struct zfile *) { return NULL; }
+struct zvolume *archive_directory_fat(struct zfile *) { return NULL; }
+struct zvolume *archive_directory_tar(struct zfile *) { return NULL; }
+struct zfile *archive_access_select(struct znode *, struct zfile *, unsigned int, int, int *retcode, int)
+{
+ if (retcode) {
+ *retcode = 0;
+ }
+ return NULL;
+}
+void archive_access_scan(struct zfile *, zfile_callback, void *, unsigned int) {}
+void archive_access_close(void *, unsigned int) {}
+struct zfile *archive_unpackzfile(struct zfile *zf) { return zf; }
+struct zfile *archive_access_lha(struct znode *) { return NULL; }
+struct zfile *archive_getzfile(struct znode *, unsigned int, int) { return NULL; }
+int isfat(uae_u8 *) { return 0; }
+#endif
+
+#ifndef SCSIEMU
+int scsi_do_disk_change(int, int, int *pollmode) { if (pollmode) *pollmode = 0; return 0; }
+uae_u32 scsi_get_cd_drive_mask(void) { return 0; }
+uae_u32 scsi_get_cd_drive_media_mask(void) { return 0; }
+int scsi_add_tape(struct uaedev_config_info *) { return -1; }
+uae_u8 *save_scsidev(int, size_t *len, uae_u8 *dst) { if (len) *len = 0; return dst; }
+uae_u8 *restore_scsidev(uae_u8 *src) { return src; }
+#endif
+
+a_inode *custom_fsdb_lookup_aino_aname(a_inode *, const TCHAR *) { return NULL; }
+a_inode *custom_fsdb_lookup_aino_nname(a_inode *, const TCHAR *) { return NULL; }
+int custom_fsdb_used_as_nname(a_inode *, const TCHAR *) { return 0; }
+
+bool gui_ask_disk(int, TCHAR *) { return false; }
+
+void filesys_addexternals(void) {}
+int target_get_volume_name(struct uaedev_mount_info *, struct uaedev_config_info *, bool, bool, int) { return 0; }
+uae_u8 *target_load_keyfile(struct uae_prefs *, const TCHAR *, int *size, TCHAR *)
+{
+ if (size) {
+ *size = 0;
+ }
+ return NULL;
+}
+uae_u32 emulib_target_getcpurate(uae_u32, uae_u32 *low)
+{
+ if (low) {
+ *low = 0;
+ }
+ return 0;
+}
+int is_touch_lightpen(void) { return 0; }
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "options.h"
+#include "uae.h"
+#include "uae/time.h"
+#include "memory.h"
+#include "newcpu.h"
+#include "host.h"
+
+#include <signal.h>
+#include <string.h>
+
+uae_u8 *natmem_offset;
+uae_u8 *natmem_reserved;
+size_t natmem_reserved_size;
+
+static volatile sig_atomic_t unix_signal_quit_requested;
+static volatile sig_atomic_t unix_exit_signal;
+static bool unix_signal_quit_dispatched;
+static bool unix_signals_installed;
+
+static void unix_alarm_handler(int)
+{
+ int sig = unix_exit_signal ? unix_exit_signal : SIGTERM;
+ _exit(128 + sig);
+}
+
+static void unix_signal_handler(int sig)
+{
+ unix_signal_quit_requested = 1;
+ unix_exit_signal = sig;
+ quit_program = -UAE_QUIT;
+ set_special_exter(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
+ alarm(2);
+}
+
+bool unix_host_quit_requested(void)
+{
+ return unix_signal_quit_requested != 0;
+}
+
+void unix_host_check_quit(void)
+{
+ if (unix_signal_quit_requested && !unix_signal_quit_dispatched) {
+ unix_signal_quit_dispatched = true;
+ uae_quit();
+ set_special(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
+ }
+}
+
+void setup_brkhandler(void)
+{
+ if (unix_signals_installed) {
+ return;
+ }
+
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = unix_signal_handler;
+
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+
+ sa.sa_handler = unix_alarm_handler;
+ sigaction(SIGALRM, &sa, NULL);
+ unix_signals_installed = true;
+}
+
+int machdep_init(void)
+{
+ setup_brkhandler();
+ uae_time_init();
+ return 1;
+}
+
+int sleep_resolution;
+
+int sleep_millis(int ms)
+{
+ if (ms <= 0) {
+ unix_host_check_quit();
+ return 0;
+ }
+ struct timespec ts;
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+ while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {
+ unix_host_check_quit();
+ if (unix_host_quit_requested()) {
+ break;
+ }
+ }
+ unix_host_check_quit();
+ return 0;
+}
+
+int sleep_millis_main(int ms)
+{
+ return sleep_millis(ms);
+}
+
+int sleep_millis_amiga(int ms)
+{
+ return sleep_millis(ms);
+}
+
+void sleep_cpu_wakeup(void)
+{
+}
+
+int target_sleep_nanos(int ns)
+{
+ if (ns <= 0) {
+ unix_host_check_quit();
+ return 0;
+ }
+ struct timespec ts;
+ ts.tv_sec = ns / 1000000000;
+ ts.tv_nsec = ns % 1000000000;
+ while (nanosleep(&ts, &ts) != 0 && errno == EINTR) {
+ unix_host_check_quit();
+ if (unix_host_quit_requested()) {
+ break;
+ }
+ }
+ unix_host_check_quit();
+ return 0;
+}
+
+uae_atomic atomic_and(volatile uae_atomic *p, uae_u32 v)
+{
+ return __sync_and_and_fetch(p, (uae_atomic)v);
+}
+
+uae_atomic atomic_or(volatile uae_atomic *p, uae_u32 v)
+{
+ return __sync_or_and_fetch(p, (uae_atomic)v);
+}
+
+uae_atomic atomic_inc(volatile uae_atomic *p)
+{
+ return __sync_add_and_fetch(p, 1);
+}
+
+uae_atomic atomic_dec(volatile uae_atomic *p)
+{
+ return __sync_sub_and_fetch(p, 1);
+}
+
+uae_u32 atomic_bit_test_and_reset(volatile uae_atomic *p, uae_u32 v)
+{
+ uae_atomic mask = (uae_atomic)1 << v;
+ uae_atomic old = __sync_fetch_and_and(p, ~mask);
+ return (old & mask) != 0;
+}
+
+uae_u32 getlocaltime(void)
+{
+ return (uae_u32)time(NULL);
+}
+
+void target_run(void) {}
+void target_quit(void) {}
+void target_restart(void) {}
+void target_reset(void) {}
+void target_cpu_speed(void) {}
+void target_addtorecent(const TCHAR*, int) {}
+void target_setdefaultstatefilename(const TCHAR*) {}
+bool target_osd_keyboard(int) { return false; }
+void target_osk_control(int, int, int, int) {}
+bool isguiactive(void) { return false; }
+bool is_mainthread(void) { return true; }
+void fpux_save(int*) {}
+void fpux_restore(int*) {}
--- /dev/null
+#ifndef WINUAE_OD_UNIX_SYSCONFIG_H
+#define WINUAE_OD_UNIX_SYSCONFIG_H
+
+#define UAE_TARGET_UNIX 1
+
+#if defined(__APPLE__)
+#define UAE_HOST_DARWIN 1
+#define MACOSX 1
+#elif defined(__linux__)
+#define UAE_HOST_LINUX 1
+#endif
+
+#if defined(__linux__) && (defined(__x86_64__) || defined(__i386__))
+#define HAVE_STRUCT_UCONTEXT_UC_MCONTEXT_GREGS 1
+#endif
+
+#if !defined(ARM64) && !defined(_M_ARM64) && !defined(__aarch64__) && \
+ (defined(__x86_64__) || defined(__amd64__) || defined(_M_X64) || \
+ defined(_M_IX86) || defined(i386) || defined(__i386) || \
+ defined(__i386__) || defined(_X86_))
+#define PCEM_VOODOO_CODEGEN 1
+#endif
+
+#define SUPPORT_THREADS 1
+#define MAX_DPATH 1000
+#define MAX_AMIGAMONITORS 4
+#define MAX_AMIGADISPLAYS 4
+#define NATMEM_OFFSET natmem_offset
+#define PACKAGE_STRING "WinUAE Unix"
+#if defined(UAE_HOST_DARWIN)
+#define WINUAE_UNIX_WINDOW_TITLE "WinUAE for macOS"
+#elif defined(UAE_HOST_LINUX)
+#define WINUAE_UNIX_WINDOW_TITLE "WinUAE for Linux"
+#else
+#define WINUAE_UNIX_WINDOW_TITLE "WinUAE for Unix"
+#endif
+
+#define GFXFILTER 1
+#define FILESYS 1
+#define UAE_FILESYS_THREADS 1
+#define AUTOCONFIG 1
+#define DEBUGGER 1
+#define ECS_DENISE 1
+#define AGA 1
+#define CD32 1
+#define CDTV 1
+#define FPUEMU 1
+#define FPU_UAE 1
+#define MMUEMU 1
+#define FULLMMU 1
+#define CPUEMU_0 1
+#define CPUEMU_11 1
+#define CPUEMU_13 1
+#define CPUEMU_20 1
+#define CPUEMU_21 1
+#define CPUEMU_22 1
+#define CPUEMU_23 1
+#define CPUEMU_24 1
+#define CPUEMU_31 1
+#define CPUEMU_32 1
+#define CPUEMU_33 1
+#define CPUEMU_34 1
+#define CPUEMU_35 1
+#define CPUEMU_40 1
+#define CPUEMU_50 1
+#define ACTION_REPLAY 1
+#define SAVESTATE 1
+#define A2091 1
+#define PICASSO96_SUPPORTED 1
+#define PICASSO96 1
+#define SCP 1
+#define FDI2RAW 1
+#define ARCADIA 1
+#define AMAX 1
+#define WITH_SOFTFLOAT 1
+#define DRIVESOUND 1
+#define PARALLEL_PORT 1
+#define SERIAL_PORT 1
+
+#define CAN_PRINTF_LONG_LONG 1
+#define RETSIGTYPE void
+#define TIME_WITH_SYS_TIME 1
+
+#define HAVE_DIRENT_H 1
+#define HAVE_FCNTL_H 1
+#define HAVE_GETCWD 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_INET_ATON 1
+#define HAVE_MKDIR 1
+#define HAVE_RMDIR 1
+#define HAVE_SELECT 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STDINT_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_MMAN_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UTIME_H 1
+#define HAVE_VFPRINTF 1
+#define HAVE_VPRINTF 1
+#define HAVE_VSPRINTF 1
+
+#define SIZEOF_CHAR 1
+#define SIZEOF_SHORT 2
+#define SIZEOF_INT 4
+#if defined(__LP64__)
+#define SIZEOF_LONG 8
+#define SIZEOF_VOID_P 8
+#define CPU_64_BIT 1
+#else
+#define SIZEOF_LONG 4
+#define SIZEOF_VOID_P 4
+#endif
+#define SIZEOF_LONG_LONG 8
+#define SIZEOF_FLOAT 4
+#define SIZEOF_DOUBLE 8
+
+#define LT_MODULE_EXT _T(".dylib")
+#if defined(UAE_HOST_LINUX)
+#undef LT_MODULE_EXT
+#define LT_MODULE_EXT _T(".so")
+#endif
+
+#define FSDB_DIR_SEPARATOR '/'
+#define FSDB_DIR_SEPARATOR_S _T("/")
+
+#ifndef PATH_MAX
+#define PATH_MAX MAX_DPATH
+#endif
+#ifndef MAX_PATH
+#define MAX_PATH MAX_DPATH
+#endif
+#ifndef MAXINT
+#define MAXINT INT_MAX
+#endif
+
+#define UAE_RAND_MAX 2147483647
+#define ZEXPORT
+#ifndef __cdecl
+#define __cdecl
+#endif
+
+#include <stdint.h>
+#include <limits.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/timeb.h>
+#include <time.h>
+
+typedef long uae_atomic;
+typedef int boolean;
+
+#ifdef WINUAE_UNIX_WITH_GFXBOARD
+typedef int8_t INT8;
+typedef uint8_t UINT8;
+typedef int16_t INT16;
+typedef uint16_t UINT16;
+typedef int32_t INT32;
+typedef uint32_t UINT32;
+typedef signed long long INT64;
+typedef unsigned long long UINT64;
+#endif
+
+#define BYTE int8_t
+#define WORD int16_t
+#define UBYTE uint8_t
+#define UWORD uint16_t
+#define USHORT uint16_t
+#define ULONG uint32_t
+#define DWORD uint32_t
+#define UINT uint32_t
+#define BOOL int
+#define HANDLE void*
+#define HWND void*
+#define HINSTANCE void*
+#define HMODULE void*
+#define WPARAM uintptr_t
+#define LPARAM intptr_t
+#define LRESULT intptr_t
+#define INT_PTR intptr_t
+#define CALLBACK
+#define WINAPI
+#define PASCAL
+#define _cdecl
+#define _stdcall
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+#define INVALID_HANDLE_VALUE ((HANDLE)-1)
+#define INVALID_SOCKET (-1)
+#define SOCKET_ERROR (-1)
+
+#ifdef WINUAE_UNIX_WITH_PCEM
+#ifndef INFINITE
+#define INFINITE 0xffffffffU
+#endif
+#ifndef WAIT_OBJECT_0
+#define WAIT_OBJECT_0 0
+#endif
+#ifndef WAIT_TIMEOUT
+#define WAIT_TIMEOUT 258
+#endif
+HANDLE CreateSemaphore(void*, int, int, const char*);
+DWORD WaitForSingleObject(HANDLE, DWORD);
+BOOL ReleaseSemaphore(HANDLE, int, void*);
+BOOL CloseHandle(HANDLE);
+#endif
+
+#define Sleep sleep_millis
+#define stricmp strcasecmp
+#define strnicmp strncasecmp
+#define _stricmp strcasecmp
+#define _strnicmp strncasecmp
+#define _tzset tzset
+#define _ftime ftime
+#define _timeb timeb
+#define _istalnum isalnum
+#define _daylight daylight
+
+static inline long uae_unix_timezone_offset(void)
+{
+ time_t now = time(NULL);
+ struct tm local_tm;
+ struct tm gm_tm;
+ localtime_r(&now, &local_tm);
+ gmtime_r(&now, &gm_tm);
+ return (long)difftime(mktime(&gm_tm), mktime(&local_tm));
+}
+
+#define _timezone uae_unix_timezone_offset()
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+#ifndef O_NDELAY
+#define O_NDELAY O_NONBLOCK
+#endif
+
+#define FILEFLAG_WRITE S_IWUSR
+#define FILEFLAG_READ S_IRUSR
+#define FILEFLAG_EXECUTE S_IXUSR
+#define FILEFLAG_DIR S_IFDIR
+
+#define UAESCSI_CDEMU 0
+#define UAESCSI_SPTI 1
+#define UAESCSI_SPTISCAN 2
+#define UAESCSI_LAST 2
+#define UAESCSI_ASPI_FIRST 3
+#define UAESCSI_ADAPTECASPI 3
+#define UAESCSI_NEROASPI 4
+#define UAESCSI_FROGASPI 5
+
+#define DRIVE_CDROM 5
+
+#endif /* WINUAE_OD_UNIX_SYSCONFIG_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_TARGET_H
+#define WINUAE_OD_UNIX_TARGET_H
+
+#define TARGET_NAME _T("unix")
+#define OPTIONSFILENAME _T("default.uae")
+
+#define TARGET_ROM_PATH _T("~/")
+#define TARGET_FLOPPY_PATH _T("~/")
+#define TARGET_HARDFILE_PATH _T("~/")
+#define TARGET_SAVESTATE_PATH _T("~/")
+
+#define DEFPRTNAME _T("lpr")
+#define DEFSERNAME _T("/dev/ttyS0")
+
+static inline int uae_deterministic_mode(void)
+{
+ return 0;
+}
+
+#endif /* WINUAE_OD_UNIX_TARGET_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_TCHAR_H
+#define WINUAE_OD_UNIX_TCHAR_H
+
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <unistd.h>
+
+typedef char TCHAR;
+
+#ifndef _T
+#define _T(x) x
+#endif
+
+static inline FILE *uae_unix_tfopen(const TCHAR *path, const TCHAR *mode)
+{
+ char unixmode[8];
+ size_t out = 0;
+ for (size_t i = 0; mode[i] != 0 && mode[i] != ',' && out + 1 < sizeof(unixmode); i++) {
+ if (mode[i] == 't' || mode[i] == ' ') {
+ continue;
+ }
+ unixmode[out++] = mode[i];
+ }
+ unixmode[out] = 0;
+ return fopen(path, unixmode[0] ? unixmode : mode);
+}
+
+#define _istdigit isdigit
+#define _istspace isspace
+#define _istupper isupper
+#define _istxdigit isxdigit
+#define _sntprintf snprintf
+#define _stscanf sscanf
+#define _stprintf sprintf
+#define _strtoui64 strtoull
+#define _tcscat strcat
+#define _tcschr strchr
+#define _tcscmp strcmp
+#define _tcscpy strcpy
+#define _tcscspn strcspn
+#define _tcsdup strdup
+#define _tcsftime strftime
+#define _tcsicmp strcasecmp
+#define _tcslen strlen
+#define _tcsncat strncat
+#define _tcsncmp strncmp
+#define _tcsncpy strncpy
+#define _tcsnicmp strncasecmp
+#define _tcsrchr strrchr
+#define _tcsspn strspn
+#define _tcsstr strstr
+#define _tcstod strtod
+#define _tcstok strtok
+#define _tcstol strtol
+#define _tcstoul strtoul
+#define _totlower tolower
+#define _totupper toupper
+#define _tprintf printf
+#define _tstof atof
+#define _tstoi atoi
+#define _tstoi64 atoll
+#define _tstol atol
+#define _tfopen uae_unix_tfopen
+#define _tfopen64 uae_unix_tfopen
+#define _ftelli64 ftello
+#define _fseeki64 fseeko
+#define _tunlink unlink
+#define _vsnprintf vsnprintf
+#define _vsntprintf vsnprintf
+#define fgetws fgets
+#define fputws fputs
+#define _wunlink unlink
+#define swscanf_s sscanf
+
+#endif /* WINUAE_OD_UNIX_TCHAR_H */
--- /dev/null
+#ifndef WINUAE_OD_UNIX_THREADDEP_THREAD_H
+#define WINUAE_OD_UNIX_THREADDEP_THREAD_H
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <time.h>
+#include <errno.h>
+#include "uae/types.h"
+
+typedef pthread_t uae_thread_id;
+
+struct uae_unix_sem {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int signaled;
+ int manual_reset;
+};
+
+typedef struct uae_unix_sem* uae_sem_t;
+
+typedef void (*uae_thread_function)(void *);
+
+void uae_sem_destroy(uae_sem_t*);
+int uae_sem_trywait(uae_sem_t*);
+int uae_sem_trywait_delay(uae_sem_t*, int);
+void uae_sem_post(uae_sem_t*);
+void uae_sem_unpost(uae_sem_t*);
+void uae_sem_wait(uae_sem_t*);
+void uae_sem_init(uae_sem_t*, int manual_reset, int initial_state);
+
+int uae_start_thread(const TCHAR *name, uae_thread_function f, void *arg, uae_thread_id *thread);
+int uae_start_thread_fast(uae_thread_function f, void *arg, uae_thread_id *thread);
+void uae_end_thread(uae_thread_id *thread);
+void uae_set_thread_priority(uae_thread_id *, int);
+uae_thread_id uae_thread_get_id(void);
+
+static inline void uae_wait_thread(uae_thread_id tid)
+{
+ pthread_join(tid, NULL);
+}
+
+#define BAD_THREAD 0
+#define UAE_THREAD_EXIT do { return; } while (0)
+
+#include "commpipe.h"
+
+#endif /* WINUAE_OD_UNIX_THREADDEP_THREAD_H */
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include "threaddep/thread.h"
+#include "uae.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void unix_sem_timeout_from_now(struct timespec *ts, int ms)
+{
+ clock_gettime(CLOCK_REALTIME, ts);
+ ts->tv_sec += ms / 1000;
+ ts->tv_nsec += (long)(ms % 1000) * 1000000L;
+ if (ts->tv_nsec >= 1000000000L) {
+ ts->tv_sec++;
+ ts->tv_nsec -= 1000000000L;
+ }
+}
+
+void uae_sem_init(uae_sem_t *sem, int manual_reset, int initial_state)
+{
+ if (!sem) {
+ return;
+ }
+ if (*sem) {
+ pthread_mutex_lock(&(*sem)->mutex);
+ (*sem)->manual_reset = manual_reset ? 1 : 0;
+ (*sem)->signaled = initial_state ? 1 : 0;
+ if ((*sem)->signaled) {
+ pthread_cond_broadcast(&(*sem)->cond);
+ }
+ pthread_mutex_unlock(&(*sem)->mutex);
+ return;
+ }
+ *sem = (uae_sem_t)calloc(1, sizeof(**sem));
+ if (!*sem) {
+ abort();
+ }
+ pthread_mutex_init(&(*sem)->mutex, NULL);
+ pthread_cond_init(&(*sem)->cond, NULL);
+ (*sem)->manual_reset = manual_reset ? 1 : 0;
+ (*sem)->signaled = initial_state ? 1 : 0;
+}
+
+void uae_sem_destroy(uae_sem_t *sem)
+{
+ if (!sem || !*sem) {
+ return;
+ }
+ pthread_cond_destroy(&(*sem)->cond);
+ pthread_mutex_destroy(&(*sem)->mutex);
+ free(*sem);
+ *sem = NULL;
+}
+
+void uae_sem_post(uae_sem_t *sem)
+{
+ if (!sem || !*sem) {
+ return;
+ }
+ pthread_mutex_lock(&(*sem)->mutex);
+ (*sem)->signaled = 1;
+ if ((*sem)->manual_reset) {
+ pthread_cond_broadcast(&(*sem)->cond);
+ } else {
+ pthread_cond_signal(&(*sem)->cond);
+ }
+ pthread_mutex_unlock(&(*sem)->mutex);
+}
+
+void uae_sem_unpost(uae_sem_t *sem)
+{
+ if (!sem || !*sem) {
+ return;
+ }
+ pthread_mutex_lock(&(*sem)->mutex);
+ (*sem)->signaled = 0;
+ pthread_mutex_unlock(&(*sem)->mutex);
+}
+
+void uae_sem_wait(uae_sem_t *sem)
+{
+ if (!sem || !*sem) {
+ return;
+ }
+ pthread_mutex_lock(&(*sem)->mutex);
+ while (!(*sem)->signaled) {
+ pthread_cond_wait(&(*sem)->cond, &(*sem)->mutex);
+ }
+ if (!(*sem)->manual_reset) {
+ (*sem)->signaled = 0;
+ }
+ pthread_mutex_unlock(&(*sem)->mutex);
+}
+
+int uae_sem_trywait(uae_sem_t *sem)
+{
+ return uae_sem_trywait_delay(sem, 0);
+}
+
+int uae_sem_trywait_delay(uae_sem_t *sem, int ms)
+{
+ int result = -1;
+ if (!sem || !*sem) {
+ return result;
+ }
+ pthread_mutex_lock(&(*sem)->mutex);
+ if (!(*sem)->signaled && ms != 0) {
+ if (ms < 0) {
+ while (!(*sem)->signaled) {
+ pthread_cond_wait(&(*sem)->cond, &(*sem)->mutex);
+ }
+ } else {
+ struct timespec ts;
+ unix_sem_timeout_from_now(&ts, ms);
+ while (!(*sem)->signaled) {
+ int err = pthread_cond_timedwait(&(*sem)->cond, &(*sem)->mutex, &ts);
+ if (err == ETIMEDOUT) {
+ break;
+ }
+ }
+ }
+ }
+ if ((*sem)->signaled) {
+ if (!(*sem)->manual_reset) {
+ (*sem)->signaled = 0;
+ }
+ result = 0;
+ }
+ pthread_mutex_unlock(&(*sem)->mutex);
+ return result;
+}
+
+struct thread_start_data {
+ uae_thread_function fn;
+ void *arg;
+};
+
+static void *thread_entry(void *data)
+{
+ thread_start_data *tsd = (thread_start_data*)data;
+ uae_thread_function fn = tsd->fn;
+ void *arg = tsd->arg;
+ free(tsd);
+ fn(arg);
+ return NULL;
+}
+
+int uae_start_thread(const TCHAR *, uae_thread_function f, void *arg, uae_thread_id *thread)
+{
+ thread_start_data *tsd = (thread_start_data*)calloc(1, sizeof(*tsd));
+ tsd->fn = f;
+ tsd->arg = arg;
+ pthread_t tid;
+ if (pthread_create(&tid, NULL, thread_entry, tsd) != 0) {
+ free(tsd);
+ return 0;
+ }
+ if (thread) {
+ *thread = tid;
+ } else {
+ pthread_detach(tid);
+ }
+ return 1;
+}
+
+int uae_start_thread_fast(uae_thread_function f, void *arg, uae_thread_id *thread)
+{
+ return uae_start_thread(NULL, f, arg, thread);
+}
+
+void uae_end_thread(uae_thread_id *thread)
+{
+ if (thread) {
+ *thread = 0;
+ }
+}
+
+void uae_set_thread_priority(uae_thread_id *, int)
+{
+}
+
+uae_thread_id uae_thread_get_id(void)
+{
+ return pthread_self();
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <stdio.h>
+
+#include "threaddep/thread.h"
+
+static bool require_int(const char *label, int actual, int expected)
+{
+ if (actual == expected) {
+ return true;
+ }
+ fprintf(stderr, "%s: expected %d, got %d\n", label, expected, actual);
+ return false;
+}
+
+int main()
+{
+ bool ok = true;
+
+ uae_sem_t sem = NULL;
+ uae_sem_init(&sem, 0, 0);
+ ok = require_int("auto initial timeout", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_post(&sem);
+ ok = require_int("auto post wakes once", uae_sem_trywait(&sem), 0) && ok;
+ ok = require_int("auto post consumed", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_post(&sem);
+ uae_sem_post(&sem);
+ ok = require_int("auto repeated post coalesces", uae_sem_trywait(&sem), 0) && ok;
+ ok = require_int("auto repeated post consumed once", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_post(&sem);
+ uae_sem_unpost(&sem);
+ ok = require_int("auto unpost clears signal", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_destroy(&sem);
+ ok = require_int("destroy clears handle", sem == NULL ? 0 : 1, 0) && ok;
+
+ uae_sem_init(&sem, 1, 0);
+ ok = require_int("manual initial timeout", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_post(&sem);
+ ok = require_int("manual post first wait", uae_sem_trywait(&sem), 0) && ok;
+ ok = require_int("manual remains signaled", uae_sem_trywait(&sem), 0) && ok;
+ uae_sem_unpost(&sem);
+ ok = require_int("manual unpost clears signal", uae_sem_trywait(&sem), -1) && ok;
+ uae_sem_init(&sem, 1, 1);
+ ok = require_int("manual reinit existing sets signal", uae_sem_trywait(&sem), 0) && ok;
+ uae_sem_destroy(&sem);
+
+ uae_sem_post(&sem);
+ uae_sem_unpost(&sem);
+ uae_sem_wait(&sem);
+ ok = require_int("null trywait fails", uae_sem_trywait(&sem), -1) && ok;
+
+ return ok ? 0 : 1;
+}
--- /dev/null
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#ifdef __APPLE__
+#include <mach/mach_time.h>
+#else
+#include <time.h>
+#endif
+
+#include "uae/time.h"
+
+static uint64_t epoch_ns;
+#ifdef __APPLE__
+static mach_timebase_info_data_t timebase;
+#endif
+
+static uint64_t monotonic_ns(void)
+{
+#ifdef __APPLE__
+ if (!timebase.denom) {
+ mach_timebase_info(&timebase);
+ }
+ uint64_t t = mach_absolute_time();
+ return t * timebase.numer / timebase.denom;
+#else
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) {
+ return 0;
+ }
+ return (uint64_t)ts.tv_sec * 1000000000ULL + (uint64_t)ts.tv_nsec;
+#endif
+}
+
+void uae_time_init(void)
+{
+ epoch_ns = monotonic_ns();
+ syncbase = 1000000;
+}
+
+void uae_time_calibrate(void)
+{
+ syncbase = 1000000;
+}
+
+uae_time_t uae_time(void)
+{
+ if (!epoch_ns) {
+ uae_time_init();
+ }
+ return (uae_time_t)((monotonic_ns() - epoch_ns) / 1000);
+}
+
+int64_t uae_time_us(void)
+{
+ if (!epoch_ns) {
+ uae_time_init();
+ }
+ return (int64_t)((monotonic_ns() - epoch_ns) / 1000);
+}
+
+int64_t uae_time_ns(void)
+{
+ if (!epoch_ns) {
+ uae_time_init();
+ }
+ return (int64_t)(monotonic_ns() - epoch_ns);
+}
+
+void uae_time_use_rdtsc(bool)
+{
+}