From 15215000f9df2ed083a694f90bdb35986df376c0 Mon Sep 17 00:00:00 2001 From: Lior Halphon Date: Thu, 27 Mar 2025 23:45:51 +0200 Subject: [PATCH] Major improvements to the SDL debugging interface, especially on Windows 1. No more separate EXE for the debugger version, the console can be freely opened at any time with ^C, and closed freely without terminating the emulator 2. On all platforms, the SDL emulator window is no longer unresponsive while the debugger is waiting for an input 3. Pressing keys in the emulator window while the debugger is waiting for inputs will trigger a terminal bell 4. Async debugging now supports Windows 7, 8.x, and earlier builds of Windows 10 --- Makefile | 33 +-- SDL/console.c | 133 +++++++--- SDL/console.h | 2 + SDL/gui.c | 2 +- SDL/gui.h | 4 + SDL/main.c | 227 ++++++++++++++++-- .../windows_associations.c | 4 +- SDL/windows_associations.h | 5 + Windows/associations.h | 2 - Windows/crt.c | 16 +- Windows/stdio.c | 84 ++++++- Windows/stdio.h | 79 +----- 12 files changed, 431 insertions(+), 160 deletions(-) rename Windows/associations.c => SDL/windows_associations.c (98%) create mode 100755 SDL/windows_associations.h delete mode 100755 Windows/associations.h diff --git a/Makefile b/Makefile index 55ae505..3377b3f 100644 --- a/Makefile +++ b/Makefile @@ -272,10 +272,9 @@ endif ifeq ($(PLATFORM),windows32) CFLAGS += -IWindows -Drandom=rand --target=x86_64-pc-windows -LDFLAGS += -lmsvcrt -lkernel32 -lcomdlg32 -luser32 -lshell32 -lole32 -ladvapi32 -ldwmapi -lSDL2main -Wl,/MANIFESTFILE:NUL --target=x86_64-pc-windows -v - -SDL_LDFLAGS := -lSDL2 -GL_LDFLAGS := -lopengl32 +LDFLAGS += -lmsvcrt -lkernel32 -Wl,/MANIFESTFILE:NUL --target=x86_64-pc-windows +SDL_LDFLAGS := -lSDL2 -lcomdlg32 -luser32 -lshell32 -lole32 -ladvapi32 -ldwmapi -lSDL2main +GL_LDFLAGS := -lopengl32 ifneq ($(REDIST_XAUDIO),) CFLAGS += -DREDIST_XAUDIO LDFLAGS += -lxaudio2_9redist @@ -326,7 +325,7 @@ LDFLAGS += -Wl,/NODEFAULTLIB:libcmt.lib ifneq ($(USE_MSVCRT_DLL),) CFLAGS += -D_NO_CRT_STDIO_INLINE -DUSE_MSVCRT_DLL $(BIN)/SDL/sameboy.exe: $(OBJ)/Windows/msvcrt.lib -$(BIN)/SDL/sameboy_debugger.exe: $(OBJ)/Windows/msvcrt.lib +$(LIBDIR)/libsameboy.dll: $(OBJ)/Windows/msvcrt.lib endif endif @@ -378,7 +377,7 @@ endif # Define our targets ifeq ($(PLATFORM),windows32) -SDL_TARGET := $(BIN)/SDL/sameboy.exe $(BIN)/SDL/sameboy_debugger.exe $(BIN)/SDL/SDL2.dll +SDL_TARGET := $(BIN)/SDL/sameboy.exe $(BIN)/SDL/SDL2.dll $(BIN)/SDL/sameboy_debugger.txt TESTER_TARGET := $(BIN)/tester/sameboy_tester.exe else SDL_TARGET := $(BIN)/SDL/sameboy @@ -452,15 +451,15 @@ endif $(OBJ)/SDL/%.dep: SDL/% -@$(MKDIR) -p $(dir $@) - $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ + $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -o $@ $(OBJ)/OpenDialog/%.dep: OpenDialog/% -@$(MKDIR) -p $(dir $@) - $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ + $(CC) $(CFLAGS) $(SDL_CFLAGS) $(GL_CFLAGS) -MT $(OBJ)/$^.o -M $^ -o $@ $(OBJ)/%.dep: % -@$(MKDIR) -p $(dir $@) - $(CC) $(CFLAGS) -MT $(OBJ)/$^.o -M $^ -c -o $@ + $(CC) $(CFLAGS) -MT $(OBJ)/$^.o -M $^ -o $@ # Compilation rules @@ -661,14 +660,18 @@ ifeq ($(CONF), release) $(CODESIGN) $@ endif -# Windows version builds two, one with a console and one without it $(BIN)/SDL/sameboy.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o -@$(MKDIR) -p $(dir $@) $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) $(GL_LDFLAGS) -Wl,/subsystem:windows - -$(BIN)/SDL/sameboy_debugger.exe: $(CORE_OBJECTS) $(SDL_OBJECTS) $(OBJ)/Windows/resources.o - -@$(MKDIR) -p $(dir $@) - $(CC) $^ -o $@ $(LDFLAGS) $(SDL_LDFLAGS) $(GL_LDFLAGS) -Wl,/subsystem:console + +$(BIN)/SDL/sameboy_debugger.txt: + echo Looking for sameboy_debugger.exe? > $@ + echo\>> $@ + echo Starting with SameBoy v1.0.1, sameboy.exe and sameboy_debugger.exe >> $@ + echo have been merged into a single executable. You can open a debugger >> $@ + echo console at any time by pressing Ctrl+C to interrupt the currently >> $@ + echo open ROM. Once you're done debugging, you can close the debugger >> $@ + echo console and resume normal execution. >> $@ ifneq ($(USE_WINDRES),) $(OBJ)/%.o: %.rc @@ -894,7 +897,7 @@ $(OBJ)/exports.def: $(OBJ)/exports $(OBJ)/names $(LIBDIR)/libsameboy.dll: $(CORE_OBJECTS) | $(OBJ)/exports.def -@$(MKDIR) -p $(dir $@) - $(CC) $(LDFLAGS) -Wl,-lldmingw -Wl,/def:$(OBJ)/exports.def -shared $(CFLAGS) $^ -o $@ + $(CC) $(LDFLAGS) -Wl,/def:$(OBJ)/exports.def -shared $(CFLAGS) $^ -o $@ # CPPP doesn't like multibyte characters, so we replace the single quote character before processing so it doesn't complain $(INC)/%.h: Core/%.h diff --git a/SDL/console.c b/SDL/console.c index dabda91..ff361a2 100644 --- a/SDL/console.c +++ b/SDL/console.c @@ -17,6 +17,7 @@ #define SGR(x) CSI(x "m") static bool initialized = false; +static bool no_csi = false; typedef struct listent_s listent_t; struct listent_s { @@ -111,12 +112,12 @@ static bool is_term(void) SetConsoleMode(stdin_handle, input_mode); SetConsoleMode(stdout_handle, output_mode); - if (before.dwCursorPosition.X != after.dwCursorPosition.X || before.dwCursorPosition.Y != after.dwCursorPosition.Y) { printf("\r \r"); - return false; + no_csi = true; } + return true; #else return getenv("TERM"); @@ -158,10 +159,12 @@ static unsigned long input_mode, output_mode; static void cleanup(void) { - printf(CSI("!p")); // reset + if (!no_csi) { + printf(CSI("!p")); // reset + } + fflush(stdout); SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), input_mode); SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), output_mode); - fflush(stdout); } static bool initialize(void) @@ -179,10 +182,14 @@ static bool initialize(void) GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &output_mode); once = true; } + if (no_csi) { + initialized = true; + return true; + } SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_VIRTUAL_TERMINAL_INPUT); SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); - printf(CSI("%dB") "\n" CSI("A") ESC("7") CSI("B"), height); + fprintf(stdout, CSI("%dB") "\n" CSI("A") ESC("7") CSI("B"), height); fflush(stdout); initialized = true; @@ -210,7 +217,9 @@ static struct termios terminal; static void cleanup(void) { - printf(CSI("!p")); // reset + if (!no_csi) { + printf(CSI("!p")); // reset + } tcsetattr(STDIN_FILENO, TCSAFLUSH, &terminal); fflush(stdout); } @@ -264,6 +273,8 @@ static bool repeat_empty = false; static bool redraw_prompt(bool force) { + if (no_csi) return true; + if (line.reverse_search) { if (!force) return false; if (line.length == 0) { @@ -525,6 +536,7 @@ restart: static pthread_mutex_t terminal_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t lines_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t lines_cond = PTHREAD_COND_INITIALIZER; +static void (*line_ready_callback)(void) = NULL; static char reverse_search_mainloop(void) { @@ -549,14 +561,6 @@ static char reverse_search_mainloop(void) delete_word(false); redraw_prompt(true); break; -#ifndef _WIN32 - case CTL('Z'): - set_line(""); - raise(SIGSTOP); - initialize(); // Reinitialize - redraw_prompt(true); - break; -#endif case CTL('H'): case 0x7F: // Backspace delete(1, false); @@ -583,6 +587,39 @@ static char reverse_search_mainloop(void) } } +static void no_csi_mainloop(void) +{ + while (true) { + char *expression = NULL; + size_t size = 0; + + errno = 0; + if (getline(&expression, &size, stdin) <= 0) { + if (!errno) { + continue; + } + return; + } + + pthread_mutex_lock(&lines_lock); + if (!expression) { + add_entry(&lines, ""); + } + else { + size_t length = strlen(expression); + if (expression[length - 1] == '\n') { + expression[length - 1] = 0; + } + add_entry(&lines, expression); + free(expression); + } + pthread_cond_signal(&lines_cond); + pthread_mutex_unlock(&lines_lock); + if (line_ready_callback) { + line_ready_callback(); + } + } +} static @@ -593,6 +630,11 @@ void * #endif mainloop(char *(*completer)(const char *substring, uintptr_t *context)) { + if (no_csi) { + no_csi_mainloop(); + return 0; + } + listent_t *history_line = NULL; uintptr_t complete_context = 0; size_t completion_length = 0; @@ -614,6 +656,10 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) else { c = raw_getc(); } + if (c == EOF) { + return 0; + } + pthread_mutex_lock(&terminal_lock); switch (c) { @@ -649,6 +695,9 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) add_entry(&lines, CON_EOF); pthread_cond_signal(&lines_cond); pthread_mutex_unlock(&lines_lock); + if (line_ready_callback) { + line_ready_callback(); + } } break; case CTL('E'): @@ -695,14 +744,6 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) delete_word(false); complete_context = completion_length = 0; break; -#ifndef _WIN32 - case CTL('Z'): - set_line(""); - complete_context = completion_length = 0; - raise(SIGSTOP); - initialize(); // Reinitialize - break; -#endif case '\r': case '\n': pthread_mutex_lock(&lines_lock); @@ -714,6 +755,9 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) } pthread_cond_signal(&lines_cond); pthread_mutex_unlock(&lines_lock); + if (line_ready_callback) { + line_ready_callback(); + } if (line.length) { listent_t *dup = reverse_find(history.last, line.content, true); if (dup) { @@ -811,22 +855,24 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) } break; case '\t': { - char temp = line.content[line.position - completion_length]; - line.content[line.position - completion_length] = 0; - char *completion = completer? completer(line.content, &complete_context) : NULL; - line.content[line.position - completion_length] = temp; - if (completion) { - if (completion_length) { - delete(completion_length, false); + if (!no_csi) { + char temp = line.content[line.position - completion_length]; + line.content[line.position - completion_length] = 0; + char *completion = completer? completer(line.content, &complete_context) : NULL; + line.content[line.position - completion_length] = temp; + if (completion) { + if (completion_length) { + delete(completion_length, false); + } + insert(completion); + completion_length = strlen(completion); + free(completion); } - insert(completion); - completion_length = strlen(completion); - free(completion); + else { + printf("\a"); + } + break; } - else { - printf("\a"); - } - break; } default: if (c >= ' ') { @@ -845,6 +891,12 @@ mainloop(char *(*completer)(const char *substring, uintptr_t *context)) return 0; } + +void CON_set_line_ready_callback(void (*callback)(void)) +{ + line_ready_callback = callback; +} + char *CON_readline(const char *new_prompt) { pthread_mutex_lock(&terminal_lock); @@ -896,8 +948,8 @@ bool CON_start(char *(*completer)(const char *substring, uintptr_t *context)) void CON_attributed_print(const char *string, CON_attributes_t *attributes) { - if (!initialized) { - printf("%s", string); + if (!initialized || no_csi) { + fprintf(stdout, "%s", string); return; } static bool pending_newline = false; @@ -1021,3 +1073,8 @@ void CON_set_repeat_empty(bool repeat) { repeat_empty = repeat; } + +bool CON_no_csi_mode(void) +{ + return no_csi; +} diff --git a/SDL/console.h b/SDL/console.h index d158988..e925b8a 100644 --- a/SDL/console.h +++ b/SDL/console.h @@ -47,3 +47,5 @@ void CON_printf(const char *fmt, ...) __printflike(1, 2); void CON_attributed_printf(const char *fmt, CON_attributes_t *attributes,...) __printflike(1, 3); void CON_set_async_prompt(const char *string); void CON_set_repeat_empty(bool repeat); +void CON_set_line_ready_callback(void (*callback)(void)); +bool CON_no_csi_mode(void); diff --git a/SDL/gui.c b/SDL/gui.c index 61f8af6..80f2e4f 100644 --- a/SDL/gui.c +++ b/SDL/gui.c @@ -14,7 +14,7 @@ #ifdef _WIN32 #include -#include +#include "windows_associations.h" #include #endif diff --git a/SDL/gui.h b/SDL/gui.h index 3438947..980d950 100644 --- a/SDL/gui.h +++ b/SDL/gui.h @@ -34,6 +34,10 @@ enum pending_command { GB_SDL_QUIT_COMMAND, GB_SDL_LOAD_STATE_FROM_FILE_COMMAND, GB_SDL_CART_SWAP_COMMAND, + GB_SDL_DEBUGGER_INTERRUPT_COMMAND, +#ifdef _WIN32 + GB_SDL_HIDE_DEBUGGER_COMMAND, +#endif }; #define GB_SDL_DEFAULT_SCALE_MAX 8 diff --git a/SDL/main.c b/SDL/main.c index 414258d..bf2976b 100644 --- a/SDL/main.c +++ b/SDL/main.c @@ -13,12 +13,11 @@ #include "shader.h" #include "audio/audio.h" #include "console.h" - -#ifndef _WIN32 #include -#else + +#ifdef _WIN32 #include -#include +#include "windows_associations.h" #endif static bool stop_on_start = false; @@ -42,6 +41,15 @@ bool uses_gl(void) return gl_context; } +void rerender_screen(void) +{ + render_texture(active_pixel_buffer, configuration.blending_mode? previous_pixel_buffer : NULL); +#ifdef _WIN32 + /* Required for some Windows 10 machines, god knows why */ + render_texture(active_pixel_buffer, configuration.blending_mode? previous_pixel_buffer : NULL); +#endif +} + void set_filename(const char *new_filename, typeof(free) *new_free_function) { if (filename && free_function) { @@ -93,22 +101,74 @@ static void handle_eof(void) static char *input_callback(GB_gameboy_t *gb) { + if (CON_no_csi_mode()) { + fprintf(stdout, "> "); + fflush(stdout); + } +#ifdef _WIN32 + DWORD pid; + GetWindowThreadProcessId(GetForegroundWindow(), &pid); + if (pid == GetCurrentProcessId()) { + BringWindowToTop(GetConsoleWindow()); + } +#endif retry: { - char *ret = CON_readline("Stopped> "); - if (strcmp(ret, CON_EOF) == 0) { - handle_eof(); - free(ret); + CON_set_async_prompt("Stopped> "); + char *ret = CON_readline_async(); + if (!ret) { +#ifdef _WIN32 + HWND window = GetConsoleWindow(); + if (pending_command == GB_SDL_HIDE_DEBUGGER_COMMAND || !window) return strdup("c"); + ShowWindow(window, SW_SHOW); +#endif + SDL_Event event; + SDL_WaitEvent(&event); + switch (event.type) { + case SDL_DISPLAYEVENT: + update_swap_interval(); + break; + + case SDL_WINDOWEVENT: { + if (event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { + update_viewport(); + } + if (event.window.type == SDL_WINDOWEVENT_MOVED +#if SDL_COMPILEDVERSION > 2018 + || event.window.type == SDL_WINDOWEVENT_DISPLAY_CHANGED +#endif + ) { + update_swap_interval(); + } + rerender_screen(); + break; + } + case SDL_QUIT: + pending_command = GB_SDL_QUIT_COMMAND; + return strdup("c"); + case SDL_KEYDOWN: + fputc('\a', stdout); + fflush(stdout); + break; + default: + break; + } goto retry; } - else { + if (strcmp(ret, CON_EOF) == 0) { + free(ret); + handle_eof(); + goto retry; + } + else if (!CON_no_csi_mode()) { CON_attributes_t attributes = {.bold = true}; CON_attributed_printf("> %s\n", &attributes, ret); } + CON_set_async_prompt("> "); return ret; } } -static char *asyc_input_callback(GB_gameboy_t *gb) +static char *async_input_callback(GB_gameboy_t *gb) { retry: { char *ret = CON_readline_async(); @@ -187,6 +247,7 @@ static void open_menu(void) } size_t previous_width = GB_get_screen_width(&gb); run_gui(true); + rerender_screen(); SDL_ShowCursor(SDL_DISABLE); if (audio_playing) { GB_audio_set_paused(false); @@ -204,6 +265,24 @@ static void open_menu(void) } } +static void console_line_ready(void) +{ + static SDL_Event event = { + .type = SDL_USEREVENT + }; + SDL_PushEvent(&event); +} + +static void configure_console(void) +{ + CON_set_async_prompt("> "); + CON_set_repeat_empty(true); + CON_set_line_ready_callback(console_line_ready); + GB_set_log_callback(&gb, log_callback); + GB_set_input_callback(&gb, input_callback); + GB_set_async_input_callback(&gb, async_input_callback); +} + static void handle_events(GB_gameboy_t *gb) { SDL_Event event; @@ -409,8 +488,7 @@ static void handle_events(GB_gameboy_t *gb) } case SDL_SCANCODE_C: if (event.type == SDL_KEYDOWN && (event.key.keysym.mod & KMOD_CTRL)) { - CON_print("^C\a\n"); - GB_debugger_break(gb); + pending_command = GB_SDL_DEBUGGER_INTERRUPT_COMMAND; } break; @@ -594,16 +672,7 @@ static void rumble(GB_gameboy_t *gb, double amp) static void debugger_interrupt(int ignore) { - if (!GB_is_inited(&gb)) exit(0); - /* ^C twice to exit */ - if (GB_debugger_is_stopped(&gb)) { - GB_save_battery(&gb, battery_save_path_ptr); - exit(0); - } - if (console_supported) { - CON_print("^C\n"); - } - GB_debugger_break(&gb); + pending_command = GB_SDL_DEBUGGER_INTERRUPT_COMMAND; } #ifndef _WIN32 @@ -638,6 +707,75 @@ static void gb_audio_callback(GB_gameboy_t *gb, GB_sample_t *sample) GB_audio_queue_sample(sample); } + +#ifdef _WIN32 +static BOOL windows_console_handler(DWORD signal) +{ + /* + Hack: prevents process termination on console close + https://twitter.com/yo_yo_yo_jbo/status/1904592584326218069 + Thanks JBO! + */ + if (signal == CTRL_C_EVENT) { + /* Only happens in no-csi mode */ + pending_command = GB_SDL_DEBUGGER_INTERRUPT_COMMAND; + TerminateThread(GetCurrentThread(), 0); + } + + pending_command = GB_SDL_HIDE_DEBUGGER_COMMAND; + console_line_ready(); + TerminateThread(GetCurrentThread(), 0); + return false; +} + +static void initialize_windows_console(void) +{ + if (AllocConsole()) { + SetConsoleTitle("SameBoy Debugger Console"); + freopen("CONIN$", "r", stdin); + setvbuf(stdin, NULL, _IONBF, 0); + freopen("CONOUT$", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); + freopen("CONOUT$", "w", stderr); + setvbuf(stderr, NULL, _IONBF, 0); + + console_supported = CON_start(completer); + if (console_supported) { + configure_console(); + } + + /* I would set a callback via SetConsoleCtrlHandler, but the function (CtrlRoutine) that + eventually calls our callback takes a lock and doesn't release it (as it expects the + process to exit afterwards). The solution is to take a more violent approach and hook + it instead. */ + +#if defined(__x86_64__) || defined(__i386__) + uint8_t *patch_address = (void *)(GetProcAddress(GetModuleHandleA("KernelBase.dll"), "CtrlRoutine") ?: + GetProcAddress(GetModuleHandleA("Kernel32.dll"), "CtrlRoutine")); +#else + uint8_t *patch_address = NULL; +#endif + if (!patch_address) { + EnableMenuItem(GetSystemMenu(GetConsoleWindow(), false), SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED); + } + else { + DWORD old_protection; + VirtualProtect(patch_address, 0x20, PAGE_READWRITE, &old_protection); + if (sizeof(&windows_console_handler) == 8) { + *(patch_address++) = 0x48; // movabs + } + *(patch_address++) = 0xb8; // mov + (*(uintptr_t *)patch_address) = (uintptr_t)&windows_console_handler; + patch_address += sizeof(&windows_console_handler); + // jmp rax/eax + *(patch_address++) = 0xff; + *(patch_address++) = 0xe0; + VirtualProtect(patch_address, 0x20, old_protection, &old_protection); + } + } +} + +#endif static bool doing_hot_swap = false; static bool handle_pending_command(void) @@ -705,6 +843,36 @@ static bool handle_pending_command(void) case GB_SDL_QUIT_COMMAND: GB_save_battery(&gb, battery_save_path_ptr); exit(0); + case GB_SDL_DEBUGGER_INTERRUPT_COMMAND: + if (!GB_is_inited(&gb)) exit(0); + +#ifdef _WIN32 + initialize_windows_console(); +#endif + + /* ^C twice to exit */ + if (GB_debugger_is_stopped(&gb)) { +#ifndef _WIN32 + GB_save_battery(&gb, battery_save_path_ptr); + exit(0); +#else + break; +#endif + } + if (console_supported) { + CON_print("^C\n"); + } + GB_debugger_break(&gb); + break; +#if _WIN32 + case GB_SDL_HIDE_DEBUGGER_COMMAND: + HWND console_window = GetConsoleWindow(); + ShowWindow(console_window, SW_HIDE); + FreeConsole(); + SDL_RaiseWindow(window); + break; +#endif + } return false; } @@ -869,10 +1037,7 @@ restart:; GB_apu_set_sample_callback(&gb, gb_audio_callback); if (console_supported) { - CON_set_async_prompt("> "); - GB_set_log_callback(&gb, log_callback); - GB_set_input_callback(&gb, input_callback); - GB_set_async_input_callback(&gb, asyc_input_callback); + configure_console(); } GB_debugger_set_reload_callback(&gb, debugger_reload_callback); @@ -1106,6 +1271,16 @@ static void handle_model_option(const char *model_string) } } +#ifdef _WIN32 +/* raise is buggy and for some reason not always go through our signal handler, so + let's just place the implementation with a direct call to debugger_interrupt. */ +int raise(int signal) +{ + debugger_interrupt(signal); + return 0; +} +#endif + int main(int argc, char **argv) { #ifdef _WIN32 diff --git a/Windows/associations.c b/SDL/windows_associations.c similarity index 98% rename from Windows/associations.c rename to SDL/windows_associations.c index 768b8c8..f5ee66d 100755 --- a/Windows/associations.c +++ b/SDL/windows_associations.c @@ -1,7 +1,8 @@ +#ifdef _WIN32 #include #include #include -#include "associations.h" +#include "windows_associations.h" static bool set_registry_string(HKEY hive, const char *folder, const char *name, const char *value) { @@ -88,3 +89,4 @@ bool GB_do_windows_association(void) return ret; } +#endif diff --git a/SDL/windows_associations.h b/SDL/windows_associations.h new file mode 100755 index 0000000..d705c1a --- /dev/null +++ b/SDL/windows_associations.h @@ -0,0 +1,5 @@ +#ifndef _WIN32 +#error windows_associations.h included while building for a different platform +#endif +#include +bool GB_do_windows_association(void); diff --git a/Windows/associations.h b/Windows/associations.h deleted file mode 100755 index e1d533d..0000000 --- a/Windows/associations.h +++ /dev/null @@ -1,2 +0,0 @@ -#include -bool GB_do_windows_association(void); diff --git a/Windows/crt.c b/Windows/crt.c index fb7cbdb..23b4f19 100755 --- a/Windows/crt.c +++ b/Windows/crt.c @@ -80,6 +80,11 @@ int _seh_filter_exe(unsigned exception_num, void *exception) return 0; } +int _seh_filter_dll(unsigned ExceptionNum, struct _EXCEPTION_POINTERS *ExceptionPtr) +{ + return 0; +} + void _set_app_type(unsigned type) { } @@ -88,4 +93,13 @@ int _set_new_mode(int new_mode) { return 0; } -#endif \ No newline at end of file + +int _execute_onexit_table(void *Table) +{ + return 0; +} + +void __std_type_info_destroy_list(void *const root_node) +{ +} +#endif diff --git a/Windows/stdio.c b/Windows/stdio.c index b45a01a..2b6d459 100755 --- a/Windows/stdio.c +++ b/Windows/stdio.c @@ -11,4 +11,86 @@ FILE *__acrt_iob_func(unsigned index) return (files[index] = fdopen(index, index == STDIN_FILENO? "r" : "w")); } -#endif \ No newline at end of file +#endif + +#ifndef __MINGW32__ +#ifndef __LIBRETRO__ +int vasprintf(char **str, const char *fmt, va_list args) +{ + size_t size = _vscprintf(fmt, args) + 1; + *str = (char*)malloc(size); + int ret = vsprintf(*str, fmt, args); + if (ret != size - 1) { + free(*str); + *str = NULL; + return -1; + } + return ret; +} + +int asprintf(char **strp, const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + int r = vasprintf(strp, fmt, args); + va_end(args); + return r; +} + +#endif +#endif + +/* This code is public domain -- Will Hartung 4/9/09 */ +intptr_t getline(char **lineptr, size_t *n, FILE *stream) +{ + char *bufptr = NULL; + char *p = bufptr; + size_t size; + int c; + + if (lineptr == NULL) { + return -1; + } + if (stream == NULL) { + return -1; + } + if (n == NULL) { + return -1; + } + bufptr = *lineptr; + size = *n; + + errno = 0; + c = fgetc(stream); + if (c == EOF) { + return -1; + } + if (bufptr == NULL) { + bufptr = (char*)malloc(128); + if (bufptr == NULL) { + return -1; + } + size = 128; + } + p = bufptr; + while (c != EOF) { + if ((p - bufptr) > (size - 1)) { + size = size + 128; + bufptr = (char*)realloc(bufptr, size); + if (bufptr == NULL) { + return -1; + } + } + *p++ = c; + if (c == '\n') { + break; + } + c = fgetc(stream); + } + + *p++ = '\0'; + *lineptr = bufptr; + *n = size; + + return p - bufptr - 1; +} diff --git a/Windows/stdio.h b/Windows/stdio.h index b8be393..e2f1c9d 100755 --- a/Windows/stdio.h +++ b/Windows/stdio.h @@ -21,83 +21,12 @@ int access(const char *filename, int mode); #ifndef __MINGW32__ #ifndef __LIBRETRO__ -static inline int vasprintf(char **str, const char *fmt, va_list args) -{ - size_t size = _vscprintf(fmt, args) + 1; - *str = (char*)malloc(size); - int ret = vsprintf(*str, fmt, args); - if (ret != size - 1) { - free(*str); - *str = NULL; - return -1; - } - return ret; -} - -static inline int asprintf(char **strp, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - int r = vasprintf(strp, fmt, args); - va_end(args); - return r; -} - +int vasprintf(char **str, const char *fmt, va_list args); +int asprintf(char **strp, const char *fmt, ...); #endif #endif -/* This code is public domain -- Will Hartung 4/9/09 */ -static inline size_t getline(char **lineptr, size_t *n, FILE *stream) -{ - char *bufptr = NULL; - char *p = bufptr; - size_t size; - int c; - - if (lineptr == NULL) { - return -1; - } - if (stream == NULL) { - return -1; - } - if (n == NULL) { - return -1; - } - bufptr = *lineptr; - size = *n; - - c = fgetc(stream); - if (c == EOF) { - return -1; - } - if (bufptr == NULL) { - bufptr = (char*)malloc(128); - if (bufptr == NULL) { - return -1; - } - size = 128; - } - p = bufptr; - while (c != EOF) { - if ((p - bufptr) > (size - 1)) { - size = size + 128; - bufptr = (char*)realloc(bufptr, size); - if (bufptr == NULL) { - return -1; - } - } - *p++ = c; - if (c == '\n') { - break; - } - c = fgetc(stream); - } - - *p++ = '\0'; - *lineptr = bufptr; - *n = size; - - return p - bufptr - 1; -} +intptr_t getline(char **lineptr, size_t *n, FILE *stream); #define snprintf _snprintf +#define printf(...) fprintf(stdout, __VA_ARGS__)