sdl12-compat: Reworked macOS SDL2 library loading.

From 270547f886deab0de8bb46f7be5dd3fabe0a01a8 Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Tue, 1 Jun 2021 10:11:21 -0400
Subject: [PATCH] Reworked macOS SDL2 library loading.

- Don't use a 4K static buffer for a path.
- Don't look up homedir if not necessary.
- Don't use sprintf since snprintf is readily available.
- Check for snprintf overflows.
- Avoid snprintf altogether when we can work from string literals.
- Try @loader_path, too.
- Reorder list of places we try to load from. I _think_ this is more correct?

References #28.

Fixes #40.
---
 src/SDL12_compat.c | 58 +++++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 21 deletions(-)

diff --git a/src/SDL12_compat.c b/src/SDL12_compat.c
index cdcdeb3..eb26cae 100644
--- a/src/SDL12_compat.c
+++ b/src/SDL12_compat.c
@@ -889,31 +889,47 @@ static char loaderror[256];
     #define strcpy_fn  strcpy
     #define sprintf_fn sprintf
     static void *Loaded_SDL20 = NULL;
-    static char framework[4096];
     #define LookupSDL20Sym(sym) dlsym(Loaded_SDL20, sym)
     #define CloseSDL20Library() { if (Loaded_SDL20) { dlclose(Loaded_SDL20); Loaded_SDL20 = NULL; } }
     static SDL_bool LoadSDL20Library(void) {
-        const char *homedir = NULL;
-        struct passwd *pwent;
-        pwent = getpwuid(getuid());
-        if (pwent) {
-            homedir = pwent->pw_dir;
-        }
-        if (!homedir) {
-            homedir = getenv("HOME");
-        }
-        if (homedir) {
-            sprintf_fn(framework, "%s%s/%s", homedir, "/Library/Frameworks", SDL20_FRAMEWORK);
-            Loaded_SDL20 = dlopen(framework, RTLD_LOCAL|RTLD_NOW);
-        }
-        if (!Loaded_SDL20) {
-            sprintf_fn(framework, "%s/%s", "/Library/Frameworks", SDL20_FRAMEWORK);
-            Loaded_SDL20 = dlopen(framework, RTLD_LOCAL|RTLD_NOW);
-        }
-        if (!Loaded_SDL20) {
-            Loaded_SDL20 = dlopen(SDL20_LIBNAME, RTLD_LOCAL|RTLD_NOW);
+        /* I don't know if this is the _right_ order to try, but this seems reasonable */
+        static const char * const dylib_locations[] = {
+            "@loader_path/" SDL20_LIBNAME, /* MyApp.app/Contents/MacOS/libSDL2-2.0.0.dylib */
+            "@loader_path/../Frameworks/" SDL20_FRAMEWORK, /* MyApp.app/Contents/Frameworks/SDL2.framework */
+            NULL,  /* /Users/username/Library/Frameworks/SDL2.framework */
+            "/Library/Frameworks" SDL20_FRAMEWORK, /* /Library/Frameworks/SDL2.framework */
+            SDL20_LIBNAME  /* oh well, anywhere the system can see the .dylib (/usr/local/lib or whatever) */
+        };
+
+        int i;
+        for (i = 0; i < SDL_arraysize(dylib_locations); i++) {
+            const char *location = dylib_locations[i];
+            if (location) {
+                Loaded_SDL20 = dlopen(location, RTLD_LOCAL|RTLD_NOW);
+            } else { /* hack to mean "try homedir" */
+                const char *homedir = NULL;
+                struct passwd *pwent = getpwuid(getuid());
+                if (pwent) {
+                    homedir = pwent->pw_dir;
+                }
+                if (!homedir) {
+                    homedir = getenv("HOME");
+                }
+                if (homedir) {
+                    char framework[512];
+                    const int rc = snprintf(framework, sizeof (framework), "%s/Library/Frameworks/" SDL20_FRAMEWORK, homedir);
+                    if ((rc > 0) && (rc < sizeof (framework))) {
+                        Loaded_SDL20 = dlopen(framework, RTLD_LOCAL|RTLD_NOW);
+                    }
+                }
+            }
+
+            if (Loaded_SDL20) {
+                return SDL_TRUE;
+            }
         }
-        return (Loaded_SDL20 != NULL) ? SDL_TRUE : SDL_FALSE;
+
+        return SDL_FALSE; /* didn't find it anywhere reasonable. :( */
     }
 #elif defined(__unix__)
     #include <dlfcn.h>